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