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