]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintbackend.c
ce35f1c654417bc4cdc1c558438220757327e492
[~andy/gtk] / gtk / gtkprintbackend.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintbackend.h: Abstract printer backend interfaces
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22 #include <string.h>
23
24 #include <gmodule.h>
25
26 #include "gtkintl.h"
27 #include "gtkmodules.h"
28 #include "gtkmarshalers.h"
29 #include "gtkprivate.h"
30 #include "gtkprintbackend.h"
31
32
33 static void gtk_print_backend_dispose      (GObject      *object);
34 static void gtk_print_backend_set_property (GObject      *object,
35                                             guint         prop_id,
36                                             const GValue *value,
37                                             GParamSpec   *pspec);
38 static void gtk_print_backend_get_property (GObject      *object,
39                                             guint         prop_id,
40                                             GValue       *value,
41                                             GParamSpec   *pspec);
42
43 struct _GtkPrintBackendPrivate
44 {
45   GHashTable *printers;
46   guint printer_list_requested : 1;
47   guint printer_list_done : 1;
48   GtkPrintBackendStatus status;
49   char **auth_info_required;
50   char **auth_info;
51 };
52
53 enum {
54   PRINTER_LIST_CHANGED,
55   PRINTER_LIST_DONE,
56   PRINTER_ADDED,
57   PRINTER_REMOVED,
58   PRINTER_STATUS_CHANGED,
59   REQUEST_PASSWORD,
60   LAST_SIGNAL
61 };
62
63 static guint signals[LAST_SIGNAL] = { 0 };
64
65 enum 
66
67   PROP_ZERO,
68   PROP_STATUS
69 };
70
71 static GObjectClass *backend_parent_class;
72
73 GQuark
74 gtk_print_backend_error_quark (void)
75 {
76   static GQuark quark = 0;
77   if (quark == 0)
78     quark = g_quark_from_static_string ("gtk-print-backend-error-quark");
79   return quark;
80 }
81
82 /*****************************************
83  *     GtkPrintBackendModule modules     *
84  *****************************************/
85
86 typedef struct _GtkPrintBackendModule GtkPrintBackendModule;
87 typedef struct _GtkPrintBackendModuleClass GtkPrintBackendModuleClass;
88
89 struct _GtkPrintBackendModule
90 {
91   GTypeModule parent_instance;
92   
93   GModule *library;
94
95   void             (*init)     (GTypeModule    *module);
96   void             (*exit)     (void);
97   GtkPrintBackend* (*create)   (void);
98
99   gchar *path;
100 };
101
102 struct _GtkPrintBackendModuleClass
103 {
104   GTypeModuleClass parent_class;
105 };
106
107 G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE)
108 #define GTK_TYPE_PRINT_BACKEND_MODULE      (_gtk_print_backend_module_get_type ())
109 #define GTK_PRINT_BACKEND_MODULE(module)   (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_PRINT_BACKEND_MODULE, GtkPrintBackendModule))
110
111 static GSList *loaded_backends;
112
113 static gboolean
114 gtk_print_backend_module_load (GTypeModule *module)
115 {
116   GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module); 
117   gpointer initp, exitp, createp;
118  
119   pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
120   if (!pb_module->library)
121     {
122       g_warning ("%s", g_module_error());
123       return FALSE;
124     }
125   
126   /* extract symbols from the lib */
127   if (!g_module_symbol (pb_module->library, "pb_module_init",
128                         &initp) ||
129       !g_module_symbol (pb_module->library, "pb_module_exit", 
130                         &exitp) ||
131       !g_module_symbol (pb_module->library, "pb_module_create", 
132                         &createp))
133     {
134       g_warning ("%s", g_module_error());
135       g_module_close (pb_module->library);
136       
137       return FALSE;
138     }
139
140   pb_module->init = initp;
141   pb_module->exit = exitp;
142   pb_module->create = createp;
143
144   /* call the printbackend's init function to let it */
145   /* setup anything it needs to set up. */
146   pb_module->init (module);
147
148   return TRUE;
149 }
150
151 static void
152 gtk_print_backend_module_unload (GTypeModule *module)
153 {
154   GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
155   
156   pb_module->exit();
157
158   g_module_close (pb_module->library);
159   pb_module->library = NULL;
160
161   pb_module->init = NULL;
162   pb_module->exit = NULL;
163   pb_module->create = NULL;
164 }
165
166 /* This only will ever be called if an error occurs during
167  * initialization
168  */
169 static void
170 gtk_print_backend_module_finalize (GObject *object)
171 {
172   GtkPrintBackendModule *module = GTK_PRINT_BACKEND_MODULE (object);
173
174   g_free (module->path);
175
176   G_OBJECT_CLASS (_gtk_print_backend_module_parent_class)->finalize (object);
177 }
178
179 static void
180 _gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
181 {
182   GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
183   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
184
185   module_class->load = gtk_print_backend_module_load;
186   module_class->unload = gtk_print_backend_module_unload;
187
188   gobject_class->finalize = gtk_print_backend_module_finalize;
189 }
190
191 static void 
192 gtk_print_backend_set_property (GObject      *object,
193                                 guint         prop_id,
194                                 const GValue *value,
195                                 GParamSpec   *pspec)
196 {
197   GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
198   GtkPrintBackendPrivate *priv = backend->priv;
199
200   switch (prop_id)
201     {
202     case PROP_STATUS:
203       priv->status = g_value_get_int (value);
204       break;
205     default:
206       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207       break;
208     }
209 }
210
211 static void 
212 gtk_print_backend_get_property (GObject    *object,
213                                 guint       prop_id,
214                                 GValue     *value,
215                                 GParamSpec *pspec)
216 {
217   GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
218   GtkPrintBackendPrivate *priv = backend->priv;
219
220   switch (prop_id)
221     {
222     case PROP_STATUS:
223       g_value_set_int (value, priv->status);
224       break;
225     default:
226       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
227       break;
228     }
229 }
230
231 static void
232 _gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
233 {
234 }
235
236 static GtkPrintBackend *
237 _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
238 {
239   GtkPrintBackend *pb;
240   
241   if (g_type_module_use (G_TYPE_MODULE (pb_module)))
242     {
243       pb = pb_module->create ();
244       g_type_module_unuse (G_TYPE_MODULE (pb_module));
245       return pb;
246     }
247   return NULL;
248 }
249
250 static GtkPrintBackend *
251 _gtk_print_backend_create (const gchar *backend_name)
252 {
253   GSList *l;
254   gchar *module_path;
255   gchar *full_name;
256   GtkPrintBackendModule *pb_module;
257   GtkPrintBackend *pb;
258
259   for (l = loaded_backends; l != NULL; l = l->next)
260     {
261       pb_module = l->data;
262       
263       if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
264         return _gtk_print_backend_module_create (pb_module);
265     }
266
267   pb = NULL;
268   if (g_module_supported ())
269     {
270       full_name = g_strconcat ("printbackend-", backend_name, NULL);
271       module_path = _gtk_find_module (full_name, "printbackends");
272       g_free (full_name);
273
274       if (module_path)
275         {
276           pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);
277
278           g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
279           pb_module->path = g_strdup (module_path);
280
281           loaded_backends = g_slist_prepend (loaded_backends,
282                                              pb_module);
283
284           pb = _gtk_print_backend_module_create (pb_module);
285
286           /* Increase use-count so that we don't unload print backends.
287            * There is a problem with module unloading in the cups module,
288            * see cups_dispatch_watch_finalize for details. 
289            */
290           g_type_module_use (G_TYPE_MODULE (pb_module));
291         }
292       
293       g_free (module_path);
294     }
295
296   return pb;
297 }
298
299 /**
300  * gtk_printer_backend_load_modules:
301  *
302  * Return value: (element-type GtkPrintBackend) (transfer container):
303  */
304 GList *
305 gtk_print_backend_load_modules (void)
306 {
307   GList *result;
308   GtkPrintBackend *backend;
309   gchar *setting;
310   gchar **backends;
311   gint i;
312   GtkSettings *settings;
313
314   result = NULL;
315
316   settings = gtk_settings_get_default ();
317   if (settings)
318     g_object_get (settings, "gtk-print-backends", &setting, NULL);
319   else
320     setting = g_strdup (GTK_PRINT_BACKENDS);
321
322   backends = g_strsplit (setting, ",", -1);
323
324   for (i = 0; backends[i]; i++)
325     {
326       g_strchug (backends[i]);
327       g_strchomp (backends[i]);
328       backend = _gtk_print_backend_create (backends[i]);
329       
330       if (backend)
331         result = g_list_append (result, backend);
332     }
333
334   g_strfreev (backends);
335   g_free (setting);
336
337   return result;
338 }
339
340 /*****************************************
341  *             GtkPrintBackend           *
342  *****************************************/
343
344 G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
345
346 static void                 fallback_printer_request_details       (GtkPrinter          *printer);
347 static gboolean             fallback_printer_mark_conflicts        (GtkPrinter          *printer,
348                                                                     GtkPrinterOptionSet *options);
349 static gboolean             fallback_printer_get_hard_margins      (GtkPrinter          *printer,
350                                                                     gdouble             *top,
351                                                                     gdouble             *bottom,
352                                                                     gdouble             *left,
353                                                                     gdouble             *right);
354 static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
355 static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
356 static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
357 static void                 request_password                       (GtkPrintBackend     *backend,
358                                                                     gpointer             auth_info_required,
359                                                                     gpointer             auth_info_default,
360                                                                     gpointer             auth_info_display,
361                                                                     gpointer             auth_info_visible,
362                                                                     const gchar         *prompt);
363   
364 static void
365 gtk_print_backend_class_init (GtkPrintBackendClass *class)
366 {
367   GObjectClass *object_class;
368   object_class = (GObjectClass *) class;
369
370   backend_parent_class = g_type_class_peek_parent (class);
371   
372   object_class->dispose = gtk_print_backend_dispose;
373   object_class->set_property = gtk_print_backend_set_property;
374   object_class->get_property = gtk_print_backend_get_property;
375
376   class->printer_request_details = fallback_printer_request_details;
377   class->printer_mark_conflicts = fallback_printer_mark_conflicts;
378   class->printer_get_hard_margins = fallback_printer_get_hard_margins;
379   class->printer_list_papers = fallback_printer_list_papers;
380   class->printer_get_default_page_size = fallback_printer_get_default_page_size;
381   class->printer_get_capabilities = fallback_printer_get_capabilities;
382   class->request_password = request_password;
383   
384   g_object_class_install_property (object_class, 
385                                    PROP_STATUS,
386                                    g_param_spec_int ("status",
387                                                      "Status",
388                                                      "The status of the print backend",
389                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
390                                                      GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
391                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
392                                                      GTK_PARAM_READWRITE)); 
393
394   g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
395   
396   signals[PRINTER_LIST_CHANGED] =
397     g_signal_new (I_("printer-list-changed"),
398                   G_TYPE_FROM_CLASS (class),
399                   G_SIGNAL_RUN_LAST,
400                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
401                   NULL, NULL,
402                   g_cclosure_marshal_VOID__VOID,
403                   G_TYPE_NONE, 0);
404   signals[PRINTER_LIST_DONE] =
405     g_signal_new (I_("printer-list-done"),
406                     G_TYPE_FROM_CLASS (class),
407                     G_SIGNAL_RUN_LAST,
408                     G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
409                     NULL, NULL,
410                     g_cclosure_marshal_VOID__VOID,
411                     G_TYPE_NONE, 0);
412   signals[PRINTER_ADDED] =
413     g_signal_new (I_("printer-added"),
414                   G_TYPE_FROM_CLASS (class),
415                   G_SIGNAL_RUN_LAST,
416                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
417                   NULL, NULL,
418                   g_cclosure_marshal_VOID__OBJECT,
419                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
420   signals[PRINTER_REMOVED] =
421     g_signal_new (I_("printer-removed"),
422                   G_TYPE_FROM_CLASS (class),
423                   G_SIGNAL_RUN_LAST,
424                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
425                   NULL, NULL,
426                   g_cclosure_marshal_VOID__OBJECT,
427                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
428   signals[PRINTER_STATUS_CHANGED] =
429     g_signal_new (I_("printer-status-changed"),
430                   G_TYPE_FROM_CLASS (class),
431                   G_SIGNAL_RUN_LAST,
432                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
433                   NULL, NULL,
434                   g_cclosure_marshal_VOID__OBJECT,
435                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
436   signals[REQUEST_PASSWORD] =
437     g_signal_new (I_("request-password"),
438                   G_TYPE_FROM_CLASS (class),
439                   G_SIGNAL_RUN_LAST,
440                   G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
441                   NULL, NULL,
442                   _gtk_marshal_VOID__POINTER_POINTER_POINTER_POINTER_STRING,
443                   G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING);
444 }
445
446 static void
447 gtk_print_backend_init (GtkPrintBackend *backend)
448 {
449   GtkPrintBackendPrivate *priv;
450
451   priv = backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend,
452                                                       GTK_TYPE_PRINT_BACKEND,
453                                                       GtkPrintBackendPrivate);
454
455   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
456                                           (GDestroyNotify) g_free,
457                                           (GDestroyNotify) g_object_unref);
458   priv->auth_info_required = NULL;
459   priv->auth_info = NULL;
460 }
461
462 static void
463 gtk_print_backend_dispose (GObject *object)
464 {
465   GtkPrintBackend *backend;
466   GtkPrintBackendPrivate *priv;
467
468   backend = GTK_PRINT_BACKEND (object);
469   priv = backend->priv;
470
471   /* We unref the printers in dispose, not in finalize so that
472    * we can break refcount cycles with gtk_print_backend_destroy 
473    */
474   if (priv->printers)
475     {
476       g_hash_table_destroy (priv->printers);
477       priv->printers = NULL;
478     }
479
480   backend_parent_class->dispose (object);
481 }
482
483
484 static void
485 fallback_printer_request_details (GtkPrinter *printer)
486 {
487 }
488
489 static gboolean
490 fallback_printer_mark_conflicts (GtkPrinter          *printer,
491                                  GtkPrinterOptionSet *options)
492 {
493   return FALSE;
494 }
495
496 static gboolean
497 fallback_printer_get_hard_margins (GtkPrinter *printer,
498                                    gdouble    *top,
499                                    gdouble    *bottom,
500                                    gdouble    *left,
501                                    gdouble    *right)
502 {
503   return FALSE;
504 }
505
506 static GList *
507 fallback_printer_list_papers (GtkPrinter *printer)
508 {
509   return NULL;
510 }
511
512 static GtkPageSetup *
513 fallback_printer_get_default_page_size (GtkPrinter *printer)
514 {
515   return NULL;
516 }
517
518 static GtkPrintCapabilities
519 fallback_printer_get_capabilities (GtkPrinter *printer)
520 {
521   return 0;
522 }
523
524
525 static void
526 printer_hash_to_sorted_active_list (const gchar  *key,
527                                     gpointer      value,
528                                     GList       **out_list)
529 {
530   GtkPrinter *printer;
531
532   printer = GTK_PRINTER (value);
533
534   if (gtk_printer_get_name (printer) == NULL)
535     return;
536
537   if (!gtk_printer_is_active (printer))
538     return;
539
540   *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
541 }
542
543
544 void
545 gtk_print_backend_add_printer (GtkPrintBackend *backend,
546                                GtkPrinter      *printer)
547 {
548   GtkPrintBackendPrivate *priv;
549   
550   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
551
552   priv = backend->priv;
553
554   if (!priv->printers)
555     return;
556   
557   g_hash_table_insert (priv->printers,
558                        g_strdup (gtk_printer_get_name (printer)), 
559                        g_object_ref (printer));
560 }
561
562 void
563 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
564                                   GtkPrinter      *printer)
565 {
566   GtkPrintBackendPrivate *priv;
567   
568   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
569   priv = backend->priv;
570
571   if (!priv->printers)
572     return;
573   
574   g_hash_table_remove (priv->printers,
575                        gtk_printer_get_name (printer));
576 }
577
578 void
579 gtk_print_backend_set_list_done (GtkPrintBackend *backend)
580 {
581   if (!backend->priv->printer_list_done)
582     {
583       backend->priv->printer_list_done = TRUE;
584       g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
585     }
586 }
587
588
589 /**
590  * gtk_print_backend_get_printer_list:
591  *
592  * Returns the current list of printers.
593  *
594  * Return value: (element-type GtkPrinter) (transfer container):
595  *   A list of #GtkPrinter objects. The list should be freed
596  *   with g_list_free().
597  */
598 GList *
599 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
600 {
601   GtkPrintBackendPrivate *priv;
602   GList *result;
603   
604   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
605
606   priv = backend->priv;
607
608   result = NULL;
609   if (priv->printers != NULL)
610     g_hash_table_foreach (priv->printers,
611                           (GHFunc) printer_hash_to_sorted_active_list,
612                           &result);
613
614   if (!priv->printer_list_requested && priv->printers != NULL)
615     {
616       if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
617         GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
618       priv->printer_list_requested = TRUE;
619     }
620
621   return result;
622 }
623
624 gboolean
625 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
626 {
627   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
628
629   return print_backend->priv->printer_list_done;
630 }
631
632 GtkPrinter *
633 gtk_print_backend_find_printer (GtkPrintBackend *backend,
634                                 const gchar     *printer_name)
635 {
636   GtkPrintBackendPrivate *priv;
637   GtkPrinter *printer;
638   
639   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
640
641   priv = backend->priv;
642
643   if (priv->printers)
644     printer = g_hash_table_lookup (priv->printers, printer_name);
645   else
646     printer = NULL;
647
648   return printer;  
649 }
650
651 void
652 gtk_print_backend_print_stream (GtkPrintBackend        *backend,
653                                 GtkPrintJob            *job,
654                                 GIOChannel             *data_io,
655                                 GtkPrintJobCompleteFunc callback,
656                                 gpointer                user_data,
657                                 GDestroyNotify          dnotify)
658 {
659   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
660
661   GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
662                                                        job,
663                                                        data_io,
664                                                        callback,
665                                                        user_data,
666                                                        dnotify);
667 }
668
669 void 
670 gtk_print_backend_set_password (GtkPrintBackend  *backend,
671                                 gchar           **auth_info_required,
672                                 gchar           **auth_info)
673 {
674   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
675
676   if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
677     GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, auth_info_required, auth_info);
678 }
679
680 static void
681 store_entry (GtkEntry  *entry,
682              gpointer   user_data)
683 {
684   gchar **data = (gchar **) user_data;
685
686   if (*data != NULL)
687     {
688       memset (*data, 0, strlen (*data));
689       g_free (*data);
690     }
691
692   *data = g_strdup (gtk_entry_get_text (entry));
693 }
694
695 static void
696 password_dialog_response (GtkWidget       *dialog,
697                           gint             response_id,
698                           GtkPrintBackend *backend)
699 {
700   GtkPrintBackendPrivate *priv = backend->priv;
701   gint i;
702
703   if (response_id == GTK_RESPONSE_OK)
704     gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info);
705   else
706     gtk_print_backend_set_password (backend, priv->auth_info_required, NULL);
707
708   for (i = 0; i < g_strv_length (priv->auth_info_required); i++)
709     if (priv->auth_info[i] != NULL)
710       {
711         memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
712         g_free (priv->auth_info[i]);
713         priv->auth_info[i] = NULL;
714       }
715   g_free (priv->auth_info);
716   priv->auth_info = NULL;
717
718   g_strfreev (priv->auth_info_required);
719
720   gtk_widget_destroy (dialog);
721
722   g_object_unref (backend);
723 }
724
725 static void
726 request_password (GtkPrintBackend  *backend,
727                   gpointer          auth_info_required,
728                   gpointer          auth_info_default,
729                   gpointer          auth_info_display,
730                   gpointer          auth_info_visible,
731                   const gchar      *prompt)
732 {
733   GtkPrintBackendPrivate *priv = backend->priv;
734   GtkWidget *dialog, *box, *main_box, *label, *icon, *vbox, *entry;
735   GtkWidget *focus = NULL;
736   GtkWidget *content_area;
737   gchar     *markup;
738   gint       length;
739   gint       i;
740   gchar    **ai_required = (gchar **) auth_info_required;
741   gchar    **ai_default = (gchar **) auth_info_default;
742   gchar    **ai_display = (gchar **) auth_info_display;
743   gboolean  *ai_visible = (gboolean *) auth_info_visible;
744
745   priv->auth_info_required = g_strdupv (ai_required);
746   length = g_strv_length (ai_required);
747   priv->auth_info = g_new0 (gchar *, length);
748
749   dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL, 
750                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
751                                          GTK_STOCK_OK, GTK_RESPONSE_OK,
752                                          NULL);
753
754   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
755
756   main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
757
758   /* Left */
759   icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
760   gtk_misc_set_alignment (GTK_MISC (icon), 0.5, 0.0);
761   gtk_misc_set_padding (GTK_MISC (icon), 6, 6);
762
763
764   /* Right */
765   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
766   gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);
767
768   /* Right - 1. */
769   label = gtk_label_new (NULL);
770   markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", prompt);
771   gtk_label_set_markup (GTK_LABEL (label), markup);
772   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
773   gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
774   g_free (markup);
775
776
777   /* Packing */
778   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
779   gtk_box_pack_start (GTK_BOX (content_area), main_box, TRUE, FALSE, 0);
780
781   gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
782   gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
783
784   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
785   
786   /* Right - 2. */
787   for (i = 0; i < length; i++)
788     {
789       priv->auth_info[i] = g_strdup (ai_default[i]);
790       if (ai_display[i] != NULL)
791         {
792           box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, TRUE, 0);
793
794           label = gtk_label_new (ai_display[i]);
795           gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
796
797           entry = gtk_entry_new ();
798           focus = entry;
799
800           if (ai_default[i] != NULL)
801             gtk_entry_set_text (GTK_ENTRY (entry), ai_default[i]);
802
803           gtk_entry_set_visibility (GTK_ENTRY (entry), ai_visible[i]);
804           gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
805
806           gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, TRUE, 6);
807
808           gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
809           gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0);
810
811           g_signal_connect (entry, "changed",
812                             G_CALLBACK (store_entry), &(priv->auth_info[i]));
813         }
814     }
815
816   if (focus != NULL)
817     {
818       gtk_widget_grab_focus (focus);
819       focus = NULL;
820     }
821
822   g_object_ref (backend);
823   g_signal_connect (G_OBJECT (dialog), "response",
824                     G_CALLBACK (password_dialog_response), backend);
825
826   gtk_widget_show_all (dialog);
827 }
828
829 void
830 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
831 {
832   /* The lifecycle of print backends and printers are tied, such that
833    * the backend owns the printers, but the printers also ref the backend.
834    * This is so that if the app has a reference to a printer its backend
835    * will be around. However, this results in a cycle, which we break
836    * with this call, which causes the print backend to release its printers.
837    */
838   g_object_run_dispose (G_OBJECT (print_backend));
839 }