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