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