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   gboolean store_auth_info;
51 };
52 
53 enum {
54   PRINTER_LIST_CHANGED,
55   PRINTER_LIST_DONE,
56   PRINTER_ADDED,
57   PRINTER_REMOVED,
58   PRINTER_STATUS_CHANGED,
59   REQUEST_PASSWORD,
60   LAST_SIGNAL
61 };
62 
63 static guint signals[LAST_SIGNAL] = { 0 };
64 
65 enum
66 {
67   PROP_ZERO,
68   PROP_STATUS
69 };
70 
71 static GObjectClass *backend_parent_class;
72 
73 GQuark
gtk_print_backend_error_quark(void)74 gtk_print_backend_error_quark (void)
75 {
76   static GQuark quark = 0;
77   if (quark == 0)
78     quark = g_quark_from_static_string ("gtk-print-backend-error-quark");
79   return quark;
80 }
81 
82 /*****************************************
83  *     GtkPrintBackendModule modules     *
84  *****************************************/
85 
86 typedef struct _GtkPrintBackendModule GtkPrintBackendModule;
87 typedef struct _GtkPrintBackendModuleClass GtkPrintBackendModuleClass;
88 
89 struct _GtkPrintBackendModule
90 {
91   GTypeModule parent_instance;
92 
93   GModule *library;
94 
95   void             (*init)     (GTypeModule    *module);
96   void             (*exit)     (void);
97   GtkPrintBackend* (*create)   (void);
98 
99   gchar *path;
100 };
101 
102 struct _GtkPrintBackendModuleClass
103 {
104   GTypeModuleClass parent_class;
105 };
106 
107 GType _gtk_print_backend_module_get_type (void);
108 
G_DEFINE_TYPE(GtkPrintBackendModule,_gtk_print_backend_module,G_TYPE_TYPE_MODULE)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
gtk_print_backend_module_unload(GTypeModule * module)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
gtk_print_backend_module_finalize(GObject * object)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
_gtk_print_backend_module_class_init(GtkPrintBackendModuleClass * class)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
gtk_print_backend_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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 = backend->priv;
201 
202   switch (prop_id)
203     {
204     case PROP_STATUS:
205       priv->status = g_value_get_int (value);
206       break;
207     default:
208       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209       break;
210     }
211 }
212 
213 static void
gtk_print_backend_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)214 gtk_print_backend_get_property (GObject    *object,
215                                 guint       prop_id,
216                                 GValue     *value,
217                                 GParamSpec *pspec)
218 {
219   GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
220   GtkPrintBackendPrivate *priv = backend->priv;
221 
222   switch (prop_id)
223     {
224     case PROP_STATUS:
225       g_value_set_int (value, priv->status);
226       break;
227     default:
228       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
229       break;
230     }
231 }
232 
233 static void
_gtk_print_backend_module_init(GtkPrintBackendModule * pb_module)234 _gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
235 {
236 }
237 
238 static GtkPrintBackend *
_gtk_print_backend_module_create(GtkPrintBackendModule * pb_module)239 _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
240 {
241   GtkPrintBackend *pb;
242 
243   if (g_type_module_use (G_TYPE_MODULE (pb_module)))
244     {
245       pb = pb_module->create ();
246       g_type_module_unuse (G_TYPE_MODULE (pb_module));
247       return pb;
248     }
249   return NULL;
250 }
251 
252 static GtkPrintBackend *
_gtk_print_backend_create(const gchar * backend_name)253 _gtk_print_backend_create (const gchar *backend_name)
254 {
255   GSList *l;
256   gchar *module_path;
257   gchar *full_name;
258   GtkPrintBackendModule *pb_module;
259   GtkPrintBackend *pb;
260 
261   for (l = loaded_backends; l != NULL; l = l->next)
262     {
263       pb_module = l->data;
264 
265       if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
266 	return _gtk_print_backend_module_create (pb_module);
267     }
268 
269   pb = NULL;
270   if (g_module_supported ())
271     {
272       full_name = g_strconcat ("printbackend-", backend_name, NULL);
273       module_path = _gtk_find_module (full_name, "printbackends");
274       g_free (full_name);
275 
276       if (module_path)
277 	{
278 	  pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);
279 
280 	  g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
281 	  pb_module->path = module_path;
282 
283 	  loaded_backends = g_slist_prepend (loaded_backends,
284 		   		             pb_module);
285 
286 	  pb = _gtk_print_backend_module_create (pb_module);
287 
288 	  /* Increase use-count so that we don't unload print backends.
289 	   * There is a problem with module unloading in the cups module,
290 	   * see cups_dispatch_watch_finalize for details.
291 	   */
292 	  g_type_module_use (G_TYPE_MODULE (pb_module));
293 	}
294     }
295 
296   return pb;
297 }
298 
299 /**
300  * gtk_print_backend_load_modules:
301  *
302  * Returns: (element-type GtkPrintBackend) (transfer container):
303  */
304 GList *
gtk_print_backend_load_modules(void)305 gtk_print_backend_load_modules (void)
306 {
307   GList *result;
308   GtkPrintBackend *backend;
309   gchar *setting;
310   gchar **backends;
311   gint i;
312   GtkSettings *settings;
313 
314   result = NULL;
315 
316   settings = gtk_settings_get_default ();
317   if (settings)
318     g_object_get (settings, "gtk-print-backends", &setting, NULL);
319   else
320     setting = g_strdup (GTK_PRINT_BACKENDS);
321 
322   backends = g_strsplit (setting, ",", -1);
323 
324   for (i = 0; backends[i]; i++)
325     {
326       backend = _gtk_print_backend_create (g_strstrip (backends[i]));
327       if (backend)
328         result = g_list_append (result, backend);
329     }
330 
331   g_strfreev (backends);
332   g_free (setting);
333 
334   return result;
335 }
336 
337 /*****************************************
338  *             GtkPrintBackend           *
339  *****************************************/
340 
341 G_DEFINE_TYPE_WITH_PRIVATE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
342 
343 static void                 fallback_printer_request_details       (GtkPrinter          *printer);
344 static gboolean             fallback_printer_mark_conflicts        (GtkPrinter          *printer,
345 								    GtkPrinterOptionSet *options);
346 static gboolean             fallback_printer_get_hard_margins      (GtkPrinter          *printer,
347                                                                     gdouble             *top,
348                                                                     gdouble             *bottom,
349                                                                     gdouble             *left,
350                                                                     gdouble             *right);
351 static gboolean             fallback_printer_get_hard_margins_for_paper_size (GtkPrinter          *printer,
352 									      GtkPaperSize        *paper_size,
353 									      gdouble             *top,
354 									      gdouble             *bottom,
355 									      gdouble             *left,
356 									      gdouble             *right);
357 static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
358 static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
359 static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
360 static void                 request_password                       (GtkPrintBackend     *backend,
361                                                                     gpointer             auth_info_required,
362                                                                     gpointer             auth_info_default,
363                                                                     gpointer             auth_info_display,
364                                                                     gpointer             auth_info_visible,
365                                                                     const gchar         *prompt,
366                                                                     gboolean             can_store_auth_info);
367 
368 static void
gtk_print_backend_class_init(GtkPrintBackendClass * class)369 gtk_print_backend_class_init (GtkPrintBackendClass *class)
370 {
371   GObjectClass *object_class;
372   object_class = (GObjectClass *) class;
373 
374   backend_parent_class = g_type_class_peek_parent (class);
375 
376   object_class->dispose = gtk_print_backend_dispose;
377   object_class->set_property = gtk_print_backend_set_property;
378   object_class->get_property = gtk_print_backend_get_property;
379 
380   class->printer_request_details = fallback_printer_request_details;
381   class->printer_mark_conflicts = fallback_printer_mark_conflicts;
382   class->printer_get_hard_margins = fallback_printer_get_hard_margins;
383   class->printer_get_hard_margins_for_paper_size = fallback_printer_get_hard_margins_for_paper_size;
384   class->printer_list_papers = fallback_printer_list_papers;
385   class->printer_get_default_page_size = fallback_printer_get_default_page_size;
386   class->printer_get_capabilities = fallback_printer_get_capabilities;
387   class->request_password = request_password;
388 
389   g_object_class_install_property (object_class,
390                                    PROP_STATUS,
391                                    g_param_spec_int ("status",
392                                                      "Status",
393                                                      "The status of the print backend",
394                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
395                                                      GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
396                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
397                                                      GTK_PARAM_READWRITE));
398 
399   signals[PRINTER_LIST_CHANGED] =
400     g_signal_new (I_("printer-list-changed"),
401 		  G_TYPE_FROM_CLASS (class),
402 		  G_SIGNAL_RUN_LAST,
403 		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
404 		  NULL, NULL,
405 		  NULL,
406 		  G_TYPE_NONE, 0);
407   signals[PRINTER_LIST_DONE] =
408     g_signal_new (I_("printer-list-done"),
409 		    G_TYPE_FROM_CLASS (class),
410 		    G_SIGNAL_RUN_LAST,
411 		    G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
412 		    NULL, NULL,
413 		    NULL,
414 		    G_TYPE_NONE, 0);
415   signals[PRINTER_ADDED] =
416     g_signal_new (I_("printer-added"),
417 		  G_TYPE_FROM_CLASS (class),
418 		  G_SIGNAL_RUN_LAST,
419 		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
420 		  NULL, NULL,
421 		  NULL,
422 		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
423   signals[PRINTER_REMOVED] =
424     g_signal_new (I_("printer-removed"),
425 		  G_TYPE_FROM_CLASS (class),
426 		  G_SIGNAL_RUN_LAST,
427 		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
428 		  NULL, NULL,
429 		  NULL,
430 		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
431   signals[PRINTER_STATUS_CHANGED] =
432     g_signal_new (I_("printer-status-changed"),
433 		  G_TYPE_FROM_CLASS (class),
434 		  G_SIGNAL_RUN_LAST,
435 		  G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
436 		  NULL, NULL,
437 		  NULL,
438 		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
439   signals[REQUEST_PASSWORD] =
440     g_signal_new (I_("request-password"),
441 		  G_TYPE_FROM_CLASS (class),
442 		  G_SIGNAL_RUN_LAST,
443 		  G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
444 		  NULL, NULL, NULL,
445 		  G_TYPE_NONE, 6, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
446 		  G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
447 }
448 
449 static void
gtk_print_backend_init(GtkPrintBackend * backend)450 gtk_print_backend_init (GtkPrintBackend *backend)
451 {
452   GtkPrintBackendPrivate *priv;
453 
454   priv = backend->priv = gtk_print_backend_get_instance_private (backend);
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
gtk_print_backend_dispose(GObject * object)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
fallback_printer_request_details(GtkPrinter * printer)486 fallback_printer_request_details (GtkPrinter *printer)
487 {
488 }
489 
490 static gboolean
fallback_printer_mark_conflicts(GtkPrinter * printer,GtkPrinterOptionSet * options)491 fallback_printer_mark_conflicts (GtkPrinter          *printer,
492 				 GtkPrinterOptionSet *options)
493 {
494   return FALSE;
495 }
496 
497 static gboolean
fallback_printer_get_hard_margins(GtkPrinter * printer,gdouble * top,gdouble * bottom,gdouble * left,gdouble * right)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 gboolean
fallback_printer_get_hard_margins_for_paper_size(GtkPrinter * printer,GtkPaperSize * paper_size,gdouble * top,gdouble * bottom,gdouble * left,gdouble * right)508 fallback_printer_get_hard_margins_for_paper_size (GtkPrinter   *printer,
509 						  GtkPaperSize *paper_size,
510 						  gdouble      *top,
511 						  gdouble      *bottom,
512 						  gdouble      *left,
513 						  gdouble      *right)
514 {
515   return FALSE;
516 }
517 
518 static GList *
fallback_printer_list_papers(GtkPrinter * printer)519 fallback_printer_list_papers (GtkPrinter *printer)
520 {
521   return NULL;
522 }
523 
524 static GtkPageSetup *
fallback_printer_get_default_page_size(GtkPrinter * printer)525 fallback_printer_get_default_page_size (GtkPrinter *printer)
526 {
527   return NULL;
528 }
529 
530 static GtkPrintCapabilities
fallback_printer_get_capabilities(GtkPrinter * printer)531 fallback_printer_get_capabilities (GtkPrinter *printer)
532 {
533   return 0;
534 }
535 
536 
537 static void
printer_hash_to_sorted_active_list(const gchar * key,gpointer value,GList ** out_list)538 printer_hash_to_sorted_active_list (const gchar  *key,
539                                     gpointer      value,
540                                     GList       **out_list)
541 {
542   GtkPrinter *printer;
543 
544   printer = GTK_PRINTER (value);
545 
546   if (gtk_printer_get_name (printer) == NULL)
547     return;
548 
549   if (!gtk_printer_is_active (printer))
550     return;
551 
552   *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
553 }
554 
555 
556 void
gtk_print_backend_add_printer(GtkPrintBackend * backend,GtkPrinter * printer)557 gtk_print_backend_add_printer (GtkPrintBackend *backend,
558 			       GtkPrinter      *printer)
559 {
560   GtkPrintBackendPrivate *priv;
561 
562   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
563 
564   priv = backend->priv;
565 
566   if (!priv->printers)
567     return;
568 
569   g_hash_table_insert (priv->printers,
570 		       g_strdup (gtk_printer_get_name (printer)),
571 		       g_object_ref (printer));
572 }
573 
574 void
gtk_print_backend_remove_printer(GtkPrintBackend * backend,GtkPrinter * printer)575 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
576 				  GtkPrinter      *printer)
577 {
578   GtkPrintBackendPrivate *priv;
579 
580   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
581   priv = backend->priv;
582 
583   if (!priv->printers)
584     return;
585 
586   g_hash_table_remove (priv->printers,
587 		       gtk_printer_get_name (printer));
588 }
589 
590 void
gtk_print_backend_set_list_done(GtkPrintBackend * backend)591 gtk_print_backend_set_list_done (GtkPrintBackend *backend)
592 {
593   if (!backend->priv->printer_list_done)
594     {
595       backend->priv->printer_list_done = TRUE;
596       g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
597     }
598 }
599 
600 
601 /**
602  * gtk_print_backend_get_printer_list:
603  *
604  * Returns the current list of printers.
605  *
606  * Returns: (element-type GtkPrinter) (transfer container):
607  *   A list of #GtkPrinter objects. The list should be freed
608  *   with g_list_free().
609  */
610 GList *
gtk_print_backend_get_printer_list(GtkPrintBackend * backend)611 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
612 {
613   GtkPrintBackendPrivate *priv;
614   GList *result;
615 
616   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
617 
618   priv = backend->priv;
619 
620   result = NULL;
621   if (priv->printers != NULL)
622     g_hash_table_foreach (priv->printers,
623                           (GHFunc) printer_hash_to_sorted_active_list,
624                           &result);
625 
626   if (!priv->printer_list_requested && priv->printers != NULL)
627     {
628       if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
629 	GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
630       priv->printer_list_requested = TRUE;
631     }
632 
633   return result;
634 }
635 
636 gboolean
gtk_print_backend_printer_list_is_done(GtkPrintBackend * print_backend)637 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
638 {
639   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
640 
641   return print_backend->priv->printer_list_done;
642 }
643 
644 GtkPrinter *
gtk_print_backend_find_printer(GtkPrintBackend * backend,const gchar * printer_name)645 gtk_print_backend_find_printer (GtkPrintBackend *backend,
646                                 const gchar     *printer_name)
647 {
648   GtkPrintBackendPrivate *priv;
649   GtkPrinter *printer;
650 
651   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
652 
653   priv = backend->priv;
654 
655   if (priv->printers)
656     printer = g_hash_table_lookup (priv->printers, printer_name);
657   else
658     printer = NULL;
659 
660   return printer;
661 }
662 
663 void
gtk_print_backend_print_stream(GtkPrintBackend * backend,GtkPrintJob * job,GIOChannel * data_io,GtkPrintJobCompleteFunc callback,gpointer user_data,GDestroyNotify dnotify)664 gtk_print_backend_print_stream (GtkPrintBackend        *backend,
665                                 GtkPrintJob            *job,
666                                 GIOChannel             *data_io,
667                                 GtkPrintJobCompleteFunc callback,
668                                 gpointer                user_data,
669 				GDestroyNotify          dnotify)
670 {
671   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
672 
673   GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
674 						       job,
675 						       data_io,
676 						       callback,
677 						       user_data,
678 						       dnotify);
679 }
680 
681 void
gtk_print_backend_set_password(GtkPrintBackend * backend,gchar ** auth_info_required,gchar ** auth_info,gboolean store_auth_info)682 gtk_print_backend_set_password (GtkPrintBackend  *backend,
683                                 gchar           **auth_info_required,
684                                 gchar           **auth_info,
685                                 gboolean          store_auth_info)
686 {
687   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
688 
689   if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
690     GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend,
691                                                          auth_info_required,
692                                                          auth_info,
693                                                          store_auth_info);
694 }
695 
696 static void
store_auth_info_toggled(GtkCheckButton * chkbtn,gpointer user_data)697 store_auth_info_toggled (GtkCheckButton *chkbtn,
698                          gpointer        user_data)
699 {
700   gboolean *data = (gboolean *) user_data;
701   *data = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chkbtn));
702 }
703 
704 static void
store_entry(GtkEntry * entry,gpointer user_data)705 store_entry (GtkEntry  *entry,
706              gpointer   user_data)
707 {
708   gchar **data = (gchar **) user_data;
709 
710   if (*data != NULL)
711     {
712       memset (*data, 0, strlen (*data));
713       g_free (*data);
714     }
715 
716   *data = g_strdup (gtk_entry_get_text (entry));
717 }
718 
719 static void
password_dialog_response(GtkWidget * dialog,gint response_id,GtkPrintBackend * backend)720 password_dialog_response (GtkWidget       *dialog,
721                           gint             response_id,
722                           GtkPrintBackend *backend)
723 {
724   GtkPrintBackendPrivate *priv = backend->priv;
725   gint i, auth_info_len;
726 
727   if (response_id == GTK_RESPONSE_OK)
728     gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info, priv->store_auth_info);
729   else
730     gtk_print_backend_set_password (backend, priv->auth_info_required, NULL, FALSE);
731 
732   /* We want to clear the data before freeing it */
733   auth_info_len = g_strv_length (priv->auth_info_required);
734   for (i = 0; i < auth_info_len; i++)
735     {
736       if (priv->auth_info[i] != NULL)
737         {
738           memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
739           g_free (priv->auth_info[i]);
740           priv->auth_info[i] = NULL;
741         }
742     }
743 
744   g_clear_pointer (&priv->auth_info, g_free);
745   g_clear_pointer (&priv->auth_info_required, g_strfreev);
746 
747   gtk_widget_destroy (dialog);
748 
749   g_object_unref (backend);
750 }
751 
752 static void
request_password(GtkPrintBackend * backend,gpointer auth_info_required,gpointer auth_info_default,gpointer auth_info_display,gpointer auth_info_visible,const gchar * prompt,gboolean can_store_auth_info)753 request_password (GtkPrintBackend  *backend,
754                   gpointer          auth_info_required,
755                   gpointer          auth_info_default,
756                   gpointer          auth_info_display,
757                   gpointer          auth_info_visible,
758                   const gchar      *prompt,
759                   gboolean          can_store_auth_info)
760 {
761   GtkPrintBackendPrivate *priv = backend->priv;
762   GtkWidget *dialog, *box, *main_box, *label, *icon, *vbox, *entry, *chkbtn;
763   GtkWidget *focus = NULL;
764   GtkWidget *content_area;
765   gchar     *markup;
766   gint       length;
767   gint       i;
768   gchar    **ai_required = (gchar **) auth_info_required;
769   gchar    **ai_default = (gchar **) auth_info_default;
770   gchar    **ai_display = (gchar **) auth_info_display;
771   gboolean  *ai_visible = (gboolean *) auth_info_visible;
772 
773   priv->auth_info_required = g_strdupv (ai_required);
774   length = g_strv_length (ai_required);
775   priv->auth_info = g_new0 (gchar *, length + 1);
776   priv->store_auth_info = FALSE;
777 
778   dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL,
779                                          _("_Cancel"), GTK_RESPONSE_CANCEL,
780                                          _("_OK"), GTK_RESPONSE_OK,
781                                          NULL);
782 
783   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
784 
785   main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
786 
787   /* Left */
788   icon = gtk_image_new_from_icon_name ("dialog-password-symbolic", GTK_ICON_SIZE_DIALOG);
789   gtk_widget_set_halign (icon, GTK_ALIGN_CENTER);
790   gtk_widget_set_valign (icon, GTK_ALIGN_START);
791   g_object_set (icon, "margin", 6, NULL);
792 
793   /* Right */
794   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
795   gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);
796 
797   /* Right - 1. */
798   label = gtk_label_new (NULL);
799   markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", prompt);
800   gtk_label_set_markup (GTK_LABEL (label), markup);
801   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
802   gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
803   g_free (markup);
804 
805 
806   /* Packing */
807   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
808   gtk_box_pack_start (GTK_BOX (content_area), main_box, TRUE, FALSE, 0);
809 
810   gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
811   gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
812 
813   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
814 
815   /* Right - 2. */
816   for (i = 0; i < length; i++)
817     {
818       priv->auth_info[i] = g_strdup (ai_default[i]);
819       if (ai_display[i] != NULL)
820         {
821           box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
822           gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
823 
824           label = gtk_label_new (ai_display[i]);
825           gtk_widget_set_halign (label, GTK_ALIGN_START);
826           gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
827 
828           entry = gtk_entry_new ();
829           focus = entry;
830 
831           if (ai_default[i] != NULL)
832             gtk_entry_set_text (GTK_ENTRY (entry), ai_default[i]);
833 
834           gtk_entry_set_visibility (GTK_ENTRY (entry), ai_visible[i]);
835           gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
836 
837           gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, TRUE, 6);
838 
839           gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
840           gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0);
841 
842           g_signal_connect (entry, "changed",
843                             G_CALLBACK (store_entry), &(priv->auth_info[i]));
844         }
845     }
846 
847   if (can_store_auth_info)
848     {
849       chkbtn = gtk_check_button_new_with_mnemonic (_("_Remember password"));
850       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chkbtn), FALSE);
851       gtk_box_pack_start (GTK_BOX (vbox), chkbtn, FALSE, FALSE, 6);
852       g_signal_connect (chkbtn, "toggled",
853                         G_CALLBACK (store_auth_info_toggled),
854                         &(priv->store_auth_info));
855     }
856 
857   if (focus != NULL)
858     {
859       gtk_widget_grab_focus (focus);
860       focus = NULL;
861     }
862 
863   g_object_ref (backend);
864   g_signal_connect (G_OBJECT (dialog), "response",
865                     G_CALLBACK (password_dialog_response), backend);
866 
867   gtk_widget_show_all (dialog);
868 }
869 
870 void
gtk_print_backend_destroy(GtkPrintBackend * print_backend)871 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
872 {
873   /* The lifecycle of print backends and printers are tied, such that
874    * the backend owns the printers, but the printers also ref the backend.
875    * This is so that if the app has a reference to a printer its backend
876    * will be around. However, this results in a cycle, which we break
877    * with this call, which causes the print backend to release its printers.
878    */
879   g_object_run_dispose (G_OBJECT (print_backend));
880 }
881