]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintbackend.c
Merge branch 'master' into client-side-windows
[~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 *hostname;
54   char *username;
55   char *password;
56 };
57
58 enum {
59   PRINTER_LIST_CHANGED,
60   PRINTER_LIST_DONE,
61   PRINTER_ADDED,
62   PRINTER_REMOVED,
63   PRINTER_STATUS_CHANGED,
64   REQUEST_PASSWORD,
65   LAST_SIGNAL
66 };
67
68 static guint signals[LAST_SIGNAL] = { 0 };
69
70 enum 
71
72   PROP_ZERO,
73   PROP_STATUS
74 };
75
76 static GObjectClass *backend_parent_class;
77
78 GQuark
79 gtk_print_backend_error_quark (void)
80 {
81   static GQuark quark = 0;
82   if (quark == 0)
83     quark = g_quark_from_static_string ("gtk-print-backend-error-quark");
84   return quark;
85 }
86
87 /*****************************************
88  *     GtkPrintBackendModule modules     *
89  *****************************************/
90
91 typedef struct _GtkPrintBackendModule GtkPrintBackendModule;
92 typedef struct _GtkPrintBackendModuleClass GtkPrintBackendModuleClass;
93
94 struct _GtkPrintBackendModule
95 {
96   GTypeModule parent_instance;
97   
98   GModule *library;
99
100   void             (*init)     (GTypeModule    *module);
101   void             (*exit)     (void);
102   GtkPrintBackend* (*create)   (void);
103
104   gchar *path;
105 };
106
107 struct _GtkPrintBackendModuleClass
108 {
109   GTypeModuleClass parent_class;
110 };
111
112 G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE)
113 #define GTK_TYPE_PRINT_BACKEND_MODULE      (_gtk_print_backend_module_get_type ())
114 #define GTK_PRINT_BACKEND_MODULE(module)   (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_PRINT_BACKEND_MODULE, GtkPrintBackendModule))
115
116 static GSList *loaded_backends;
117
118 static gboolean
119 gtk_print_backend_module_load (GTypeModule *module)
120 {
121   GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module); 
122   gpointer initp, exitp, createp;
123  
124   pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
125   if (!pb_module->library)
126     {
127       g_warning ("%s", g_module_error());
128       return FALSE;
129     }
130   
131   /* extract symbols from the lib */
132   if (!g_module_symbol (pb_module->library, "pb_module_init",
133                         &initp) ||
134       !g_module_symbol (pb_module->library, "pb_module_exit", 
135                         &exitp) ||
136       !g_module_symbol (pb_module->library, "pb_module_create", 
137                         &createp))
138     {
139       g_warning ("%s", g_module_error());
140       g_module_close (pb_module->library);
141       
142       return FALSE;
143     }
144
145   pb_module->init = initp;
146   pb_module->exit = exitp;
147   pb_module->create = createp;
148
149   /* call the printbackend's init function to let it */
150   /* setup anything it needs to set up. */
151   pb_module->init (module);
152
153   return TRUE;
154 }
155
156 static void
157 gtk_print_backend_module_unload (GTypeModule *module)
158 {
159   GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
160   
161   pb_module->exit();
162
163   g_module_close (pb_module->library);
164   pb_module->library = NULL;
165
166   pb_module->init = NULL;
167   pb_module->exit = NULL;
168   pb_module->create = NULL;
169 }
170
171 /* This only will ever be called if an error occurs during
172  * initialization
173  */
174 static void
175 gtk_print_backend_module_finalize (GObject *object)
176 {
177   GtkPrintBackendModule *module = GTK_PRINT_BACKEND_MODULE (object);
178
179   g_free (module->path);
180
181   G_OBJECT_CLASS (_gtk_print_backend_module_parent_class)->finalize (object);
182 }
183
184 static void
185 _gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
186 {
187   GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
188   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
189
190   module_class->load = gtk_print_backend_module_load;
191   module_class->unload = gtk_print_backend_module_unload;
192
193   gobject_class->finalize = gtk_print_backend_module_finalize;
194 }
195
196 static void 
197 gtk_print_backend_set_property (GObject      *object,
198                                 guint         prop_id,
199                                 const GValue *value,
200                                 GParamSpec   *pspec)
201 {
202   GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
203   GtkPrintBackendPrivate *priv;
204
205   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
206
207   switch (prop_id)
208     {
209     case PROP_STATUS:
210       priv->status = g_value_get_int (value);
211       break;
212     default:
213       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
214       break;
215     }
216 }
217
218 static void 
219 gtk_print_backend_get_property (GObject    *object,
220                                 guint       prop_id,
221                                 GValue     *value,
222                                 GParamSpec *pspec)
223 {
224   GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
225   GtkPrintBackendPrivate *priv;
226
227   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
228
229   switch (prop_id)
230     {
231     case PROP_STATUS:
232       g_value_set_int (value, priv->status);
233       break;
234     default:
235       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
236       break;
237     }
238 }
239
240 static void
241 _gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
242 {
243 }
244
245 static GtkPrintBackend *
246 _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
247 {
248   GtkPrintBackend *pb;
249   
250   if (g_type_module_use (G_TYPE_MODULE (pb_module)))
251     {
252       pb = pb_module->create ();
253       g_type_module_unuse (G_TYPE_MODULE (pb_module));
254       return pb;
255     }
256   return NULL;
257 }
258
259 static GtkPrintBackend *
260 _gtk_print_backend_create (const gchar *backend_name)
261 {
262   GSList *l;
263   gchar *module_path;
264   gchar *full_name;
265   GtkPrintBackendModule *pb_module;
266   GtkPrintBackend *pb;
267
268   for (l = loaded_backends; l != NULL; l = l->next)
269     {
270       pb_module = l->data;
271       
272       if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
273         return _gtk_print_backend_module_create (pb_module);
274     }
275
276   pb = NULL;
277   if (g_module_supported ())
278     {
279       full_name = g_strconcat ("printbackend-", backend_name, NULL);
280       module_path = _gtk_find_module (full_name, "printbackends");
281       g_free (full_name);
282
283       if (module_path)
284         {
285           pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);
286
287           g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
288           pb_module->path = g_strdup (module_path);
289
290           loaded_backends = g_slist_prepend (loaded_backends,
291                                              pb_module);
292
293           pb = _gtk_print_backend_module_create (pb_module);
294
295           /* Increase use-count so that we don't unload print backends.
296            * There is a problem with module unloading in the cups module,
297            * see cups_dispatch_watch_finalize for details. 
298            */
299           g_type_module_use (G_TYPE_MODULE (pb_module));
300         }
301       
302       g_free (module_path);
303     }
304
305   return pb;
306 }
307
308 GList *
309 gtk_print_backend_load_modules (void)
310 {
311   GList *result;
312   GtkPrintBackend *backend;
313   gchar *setting;
314   gchar **backends;
315   gint i;
316   GtkSettings *settings;
317
318   result = NULL;
319
320   settings = gtk_settings_get_default ();
321   if (settings)
322     g_object_get (settings, "gtk-print-backends", &setting, NULL);
323   else
324     setting = g_strdup (GTK_PRINT_BACKENDS);
325
326   backends = g_strsplit (setting, ",", -1);
327
328   for (i = 0; backends[i]; i++)
329     {
330       g_strchug (backends[i]);
331       g_strchomp (backends[i]);
332       backend = _gtk_print_backend_create (backends[i]);
333       
334       if (backend)
335         result = g_list_append (result, backend);
336     }
337
338   g_strfreev (backends);
339   g_free (setting);
340
341   return result;
342 }
343
344 /*****************************************
345  *             GtkPrintBackend           *
346  *****************************************/
347
348 G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
349
350 static void                 fallback_printer_request_details       (GtkPrinter          *printer);
351 static gboolean             fallback_printer_mark_conflicts        (GtkPrinter          *printer,
352                                                                     GtkPrinterOptionSet *options);
353 static void                 fallback_printer_get_hard_margins      (GtkPrinter          *printer,
354                                                                     gdouble             *top,
355                                                                     gdouble             *bottom,
356                                                                     gdouble             *left,
357                                                                     gdouble             *right);
358 static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
359 static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
360 static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
361 static void                 request_password                       (GtkPrintBackend     *backend,
362                                                                     const gchar         *hostname,
363                                                                     const gchar         *username,
364                                                                     const gchar         *prompt);
365   
366 static void
367 gtk_print_backend_class_init (GtkPrintBackendClass *class)
368 {
369   GObjectClass *object_class;
370   object_class = (GObjectClass *) class;
371
372   backend_parent_class = g_type_class_peek_parent (class);
373   
374   object_class->dispose = gtk_print_backend_dispose;
375   object_class->set_property = gtk_print_backend_set_property;
376   object_class->get_property = gtk_print_backend_get_property;
377
378   class->printer_request_details = fallback_printer_request_details;
379   class->printer_mark_conflicts = fallback_printer_mark_conflicts;
380   class->printer_get_hard_margins = fallback_printer_get_hard_margins;
381   class->printer_list_papers = fallback_printer_list_papers;
382   class->printer_get_default_page_size = fallback_printer_get_default_page_size;
383   class->printer_get_capabilities = fallback_printer_get_capabilities;
384   class->request_password = request_password;
385   
386   g_object_class_install_property (object_class, 
387                                    PROP_STATUS,
388                                    g_param_spec_int ("status",
389                                                      "Status",
390                                                      "The status of the print backend",
391                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
392                                                      GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
393                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
394                                                      GTK_PARAM_READWRITE)); 
395
396   g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
397   
398   signals[PRINTER_LIST_CHANGED] =
399     g_signal_new (I_("printer-list-changed"),
400                   G_TYPE_FROM_CLASS (class),
401                   G_SIGNAL_RUN_LAST,
402                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
403                   NULL, NULL,
404                   g_cclosure_marshal_VOID__VOID,
405                   G_TYPE_NONE, 0);
406   signals[PRINTER_LIST_DONE] =
407     g_signal_new (I_("printer-list-done"),
408                     G_TYPE_FROM_CLASS (class),
409                     G_SIGNAL_RUN_LAST,
410                     G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
411                     NULL, NULL,
412                     g_cclosure_marshal_VOID__VOID,
413                     G_TYPE_NONE, 0);
414   signals[PRINTER_ADDED] =
415     g_signal_new (I_("printer-added"),
416                   G_TYPE_FROM_CLASS (class),
417                   G_SIGNAL_RUN_LAST,
418                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
419                   NULL, NULL,
420                   g_cclosure_marshal_VOID__OBJECT,
421                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
422   signals[PRINTER_REMOVED] =
423     g_signal_new (I_("printer-removed"),
424                   G_TYPE_FROM_CLASS (class),
425                   G_SIGNAL_RUN_LAST,
426                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
427                   NULL, NULL,
428                   g_cclosure_marshal_VOID__OBJECT,
429                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
430   signals[PRINTER_STATUS_CHANGED] =
431     g_signal_new (I_("printer-status-changed"),
432                   G_TYPE_FROM_CLASS (class),
433                   G_SIGNAL_RUN_LAST,
434                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
435                   NULL, NULL,
436                   g_cclosure_marshal_VOID__OBJECT,
437                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
438   signals[REQUEST_PASSWORD] =
439     g_signal_new (I_("request-password"),
440                   G_TYPE_FROM_CLASS (class),
441                   G_SIGNAL_RUN_LAST,
442                   G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
443                   NULL, NULL,
444                   _gtk_marshal_VOID__STRING_STRING_STRING,
445                   G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
446 }
447
448 static void
449 gtk_print_backend_init (GtkPrintBackend *backend)
450 {
451   GtkPrintBackendPrivate *priv;
452
453   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
454
455   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
456                                           (GDestroyNotify) g_free,
457                                           (GDestroyNotify) g_object_unref);
458   priv->hostname = NULL;
459   priv->username = NULL;
460   priv->password = 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 void
498 fallback_printer_get_hard_margins (GtkPrinter *printer,
499                                    gdouble    *top,
500                                    gdouble    *bottom,
501                                    gdouble    *left,
502                                    gdouble    *right)
503 {
504   *top = 0;
505   *bottom = 0;
506   *left = 0;
507   *right = 0;
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 GList *
594 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
595 {
596   GtkPrintBackendPrivate *priv;
597   GList *result;
598   
599   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
600
601   priv = backend->priv;
602
603   result = NULL;
604   if (priv->printers != NULL)
605     g_hash_table_foreach (priv->printers,
606                           (GHFunc) printer_hash_to_sorted_active_list,
607                           &result);
608
609   if (!priv->printer_list_requested && priv->printers != NULL)
610     {
611       if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
612         GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
613       priv->printer_list_requested = TRUE;
614     }
615
616   return result;
617 }
618
619 gboolean
620 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
621 {
622   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
623
624   return print_backend->priv->printer_list_done;
625 }
626
627 GtkPrinter *
628 gtk_print_backend_find_printer (GtkPrintBackend *backend,
629                                 const gchar     *printer_name)
630 {
631   GtkPrintBackendPrivate *priv;
632   GtkPrinter *printer;
633   
634   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
635
636   priv = backend->priv;
637
638   if (priv->printers)
639     printer = g_hash_table_lookup (priv->printers, printer_name);
640   else
641     printer = NULL;
642
643   return printer;  
644 }
645
646 void
647 gtk_print_backend_print_stream (GtkPrintBackend        *backend,
648                                 GtkPrintJob            *job,
649                                 GIOChannel             *data_io,
650                                 GtkPrintJobCompleteFunc callback,
651                                 gpointer                user_data,
652                                 GDestroyNotify          dnotify)
653 {
654   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
655
656   GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
657                                                        job,
658                                                        data_io,
659                                                        callback,
660                                                        user_data,
661                                                        dnotify);
662 }
663
664 void 
665 gtk_print_backend_set_password (GtkPrintBackend *backend,
666                                 const gchar     *hostname,
667                                 const gchar     *username,
668                                 const gchar     *password)
669 {
670   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
671
672   if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
673     GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, hostname, username, password);
674 }
675
676 static void
677 store_password (GtkEntry        *entry,
678                 GtkPrintBackend *backend)
679 {
680   GtkPrintBackendPrivate *priv = backend->priv;
681
682   if (priv->password != NULL)
683     {
684       memset (priv->password, 0, strlen (priv->password));
685       g_free (priv->password);
686     }
687
688   priv->password = g_strdup (gtk_entry_get_text (entry));
689 }
690
691 static void
692 store_username (GtkEntry        *entry,
693                 GtkPrintBackend *backend)
694 {
695   GtkPrintBackendPrivate *priv = backend->priv;
696
697   g_free (priv->username);
698   priv->username = g_strdup (gtk_entry_get_text (entry));
699 }
700
701 static void
702 password_dialog_response (GtkWidget       *dialog,
703                           gint             response_id,
704                           GtkPrintBackend *backend)
705 {
706   GtkPrintBackendPrivate *priv = backend->priv;
707
708   if (response_id == GTK_RESPONSE_OK)
709     gtk_print_backend_set_password (backend, priv->hostname, priv->username, priv->password);
710   else
711     gtk_print_backend_set_password (backend, priv->hostname, priv->username, NULL);
712
713   if (priv->password != NULL)
714     {
715       memset (priv->password, 0, strlen (priv->password));
716       g_free (priv->password);
717       priv->password = NULL;
718     }
719
720   g_free (priv->username);
721   priv->username = NULL;
722
723   gtk_widget_destroy (dialog);
724
725   g_object_unref (backend);
726 }
727
728 static void
729 request_password (GtkPrintBackend *backend,
730                   const gchar     *hostname,
731                   const gchar     *username,
732                   const gchar     *prompt)
733 {
734   GtkPrintBackendPrivate *priv = backend->priv;
735   GtkWidget *dialog, *username_box, *password_box, *main_box, *label, *icon, *vbox,
736             *password_prompt, *username_prompt,
737             *password_entry, *username_entry;
738   gchar     *markup;
739
740   dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL, 
741                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
742                                          GTK_STOCK_OK, GTK_RESPONSE_OK,
743                                          NULL);
744
745   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
746   gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
747
748   main_box = gtk_hbox_new (FALSE, 0);
749
750   /* Left */
751   icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
752   gtk_misc_set_alignment (GTK_MISC (icon), 0.5, 0.0);
753   gtk_misc_set_padding (GTK_MISC (icon), 6, 6);
754
755
756   /* Right */
757   vbox = gtk_vbox_new (FALSE, 0);
758   gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);
759
760   /* Right - 1. */
761   label = gtk_label_new (NULL);
762   markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", prompt);
763   gtk_label_set_markup (GTK_LABEL (label), markup);
764   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
765   gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
766   g_free (markup);
767
768
769   /* Right - 2. */
770   username_box = gtk_hbox_new (TRUE, 0);
771
772   username_prompt = gtk_label_new (_("Username:"));
773   gtk_misc_set_alignment (GTK_MISC (username_prompt), 0.0, 0.5);
774
775   username_entry = gtk_entry_new ();
776   gtk_entry_set_text (GTK_ENTRY (username_entry), username);
777
778
779   /* Right - 3. */
780   password_box = gtk_hbox_new (TRUE, 0);
781
782   password_prompt = gtk_label_new (_("Password:"));
783   gtk_misc_set_alignment (GTK_MISC (password_prompt), 0.0, 0.5);
784
785   password_entry = gtk_entry_new ();
786   gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
787   gtk_entry_set_activates_default (GTK_ENTRY (password_entry), TRUE);
788
789
790   /* Packing */
791   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_box, TRUE, FALSE, 0);
792
793   gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
794   gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
795
796   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
797   gtk_box_pack_start (GTK_BOX (vbox), username_box, FALSE, TRUE, 6);
798   gtk_box_pack_start (GTK_BOX (vbox), password_box, FALSE, TRUE, 6);
799
800   gtk_box_pack_start (GTK_BOX (username_box), username_prompt, TRUE, TRUE, 0);
801   gtk_box_pack_start (GTK_BOX (username_box), username_entry, TRUE, TRUE, 0);
802
803   gtk_box_pack_start (GTK_BOX (password_box), password_prompt, TRUE, TRUE, 0);
804   gtk_box_pack_start (GTK_BOX (password_box), password_entry, TRUE, TRUE, 0);
805
806
807   gtk_widget_grab_focus (password_entry);
808
809   priv->hostname = g_strdup (hostname);
810   priv->username = g_strdup (username);
811
812   g_signal_connect (password_entry, "changed",
813                     G_CALLBACK (store_password), backend);
814
815   g_signal_connect (username_entry, "changed",
816                     G_CALLBACK (store_username), backend);
817
818   g_object_ref (backend);
819   g_signal_connect (G_OBJECT (dialog), "response",
820                     G_CALLBACK (password_dialog_response), backend);
821
822   gtk_widget_show_all (dialog);
823 }
824
825 void
826 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
827 {
828   /* The lifecycle of print backends and printers are tied, such that
829    * the backend owns the printers, but the printers also ref the backend.
830    * This is so that if the app has a reference to a printer its backend
831    * will be around. However, this results in a cycle, which we break
832    * with this call, which causes the print backend to release its printers.
833    */
834   g_object_run_dispose (G_OBJECT (print_backend));
835 }
836
837
838 #define __GTK_PRINT_BACKEND_C__
839 #include "gtkaliasdef.c"