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