]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintbackend.c
2889b94fbaf22ab40324aebc1a2f988341372831
[~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 "gtkprivate.h"
29 #include "gtkprintbackend.h"
30 #include "gtkprinter-private.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 };
53
54 enum {
55   PRINTER_LIST_CHANGED,
56   PRINTER_LIST_DONE,
57   PRINTER_ADDED,
58   PRINTER_REMOVED,
59   PRINTER_STATUS_CHANGED,
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
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 G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE)
108 #define GTK_TYPE_PRINT_BACKEND_MODULE      (_gtk_print_backend_module_get_type ())
109 #define GTK_PRINT_BACKEND_MODULE(module)   (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_PRINT_BACKEND_MODULE, GtkPrintBackendModule))
110
111 static GSList *loaded_backends;
112
113 static gboolean
114 gtk_print_backend_module_load (GTypeModule *module)
115 {
116   GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module); 
117   gpointer initp, exitp, createp;
118  
119   pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
120   if (!pb_module->library)
121     {
122       g_warning ("%s", g_module_error());
123       return FALSE;
124     }
125   
126   /* extract symbols from the lib */
127   if (!g_module_symbol (pb_module->library, "pb_module_init",
128                         &initp) ||
129       !g_module_symbol (pb_module->library, "pb_module_exit", 
130                         &exitp) ||
131       !g_module_symbol (pb_module->library, "pb_module_create", 
132                         &createp))
133     {
134       g_warning ("%s", g_module_error());
135       g_module_close (pb_module->library);
136       
137       return FALSE;
138     }
139
140   pb_module->init = initp;
141   pb_module->exit = exitp;
142   pb_module->create = createp;
143
144   /* call the printbackend's init function to let it */
145   /* setup anything it needs to set up. */
146   pb_module->init (module);
147
148   return TRUE;
149 }
150
151 static void
152 gtk_print_backend_module_unload (GTypeModule *module)
153 {
154   GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
155   
156   pb_module->exit();
157
158   g_module_close (pb_module->library);
159   pb_module->library = NULL;
160
161   pb_module->init = NULL;
162   pb_module->exit = NULL;
163   pb_module->create = NULL;
164 }
165
166 /* This only will ever be called if an error occurs during
167  * initialization
168  */
169 static void
170 gtk_print_backend_module_finalize (GObject *object)
171 {
172   GtkPrintBackendModule *module = GTK_PRINT_BACKEND_MODULE (object);
173
174   g_free (module->path);
175
176   G_OBJECT_CLASS (_gtk_print_backend_module_parent_class)->finalize (object);
177 }
178
179 static void
180 _gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
181 {
182   GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
183   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
184
185   module_class->load = gtk_print_backend_module_load;
186   module_class->unload = gtk_print_backend_module_unload;
187
188   gobject_class->finalize = gtk_print_backend_module_finalize;
189 }
190
191 static void 
192 gtk_print_backend_set_property (GObject      *object,
193                                 guint         prop_id,
194                                 const GValue *value,
195                                 GParamSpec   *pspec)
196 {
197   GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
198   GtkPrintBackendPrivate *priv;
199
200   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
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 
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;
221
222   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
223
224   switch (prop_id)
225     {
226     case PROP_STATUS:
227       g_value_set_int (value, priv->status);
228       break;
229     default:
230       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231       break;
232     }
233 }
234
235 static void
236 _gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
237 {
238 }
239
240 static GtkPrintBackend *
241 _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
242 {
243   GtkPrintBackend *pb;
244   
245   if (g_type_module_use (G_TYPE_MODULE (pb_module)))
246     {
247       pb = pb_module->create ();
248       g_type_module_unuse (G_TYPE_MODULE (pb_module));
249       return pb;
250     }
251   return NULL;
252 }
253
254 static GtkPrintBackend *
255 _gtk_print_backend_create (const gchar *backend_name)
256 {
257   GSList *l;
258   gchar *module_path;
259   gchar *full_name;
260   GtkPrintBackendModule *pb_module;
261   GtkPrintBackend *pb;
262
263   for (l = loaded_backends; l != NULL; l = l->next)
264     {
265       pb_module = l->data;
266       
267       if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
268         return _gtk_print_backend_module_create (pb_module);
269     }
270
271   pb = NULL;
272   if (g_module_supported ())
273     {
274       full_name = g_strconcat ("printbackend-", backend_name, NULL);
275       module_path = _gtk_find_module (full_name, "printbackends");
276       g_free (full_name);
277
278       if (module_path)
279         {
280           pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);
281
282           g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
283           pb_module->path = g_strdup (module_path);
284
285           loaded_backends = g_slist_prepend (loaded_backends,
286                                              pb_module);
287
288           pb = _gtk_print_backend_module_create (pb_module);
289
290           /* Increase use-count so that we don't unload print backends.
291            * There is a problem with module unloading in the cups module,
292            * see cups_dispatch_watch_finalize for details. 
293            */
294           g_type_module_use (G_TYPE_MODULE (pb_module));
295         }
296       
297       g_free (module_path);
298     }
299
300   return pb;
301 }
302
303 GList *
304 gtk_print_backend_load_modules (void)
305 {
306   GList *result;
307   GtkPrintBackend *backend;
308   gchar *setting;
309   gchar **backends;
310   gint i;
311   GtkSettings *settings;
312
313   result = NULL;
314
315   settings = gtk_settings_get_default ();
316   if (settings)
317     g_object_get (settings, "gtk-print-backends", &setting, NULL);
318   else
319     setting = g_strdup (GTK_PRINT_BACKENDS);
320
321   backends = g_strsplit (setting, ",", -1);
322
323   for (i = 0; backends[i]; i++)
324     {
325       g_strchug (backends[i]);
326       g_strchomp (backends[i]);
327       backend = _gtk_print_backend_create (backends[i]);
328       
329       if (backend)
330         result = g_list_append (result, backend);
331     }
332
333   g_strfreev (backends);
334   g_free (setting);
335
336   return result;
337 }
338
339 /*****************************************
340  *             GtkPrintBackend           *
341  *****************************************/
342
343 G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
344
345 static void                 fallback_printer_request_details       (GtkPrinter          *printer);
346 static gboolean             fallback_printer_mark_conflicts        (GtkPrinter          *printer,
347                                                                     GtkPrinterOptionSet *options);
348 static void                 fallback_printer_get_hard_margins      (GtkPrinter          *printer,
349                                                                     gdouble             *top,
350                                                                     gdouble             *bottom,
351                                                                     gdouble             *left,
352                                                                     gdouble             *right);
353 static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
354 static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
355 static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
356   
357 static void
358 gtk_print_backend_class_init (GtkPrintBackendClass *class)
359 {
360   GObjectClass *object_class;
361   object_class = (GObjectClass *) class;
362
363   backend_parent_class = g_type_class_peek_parent (class);
364   
365   object_class->dispose = gtk_print_backend_dispose;
366   object_class->set_property = gtk_print_backend_set_property;
367   object_class->get_property = gtk_print_backend_get_property;
368
369   class->printer_request_details = fallback_printer_request_details;
370   class->printer_mark_conflicts = fallback_printer_mark_conflicts;
371   class->printer_get_hard_margins = fallback_printer_get_hard_margins;
372   class->printer_list_papers = fallback_printer_list_papers;
373   class->printer_get_default_page_size = fallback_printer_get_default_page_size;
374   class->printer_get_capabilities = fallback_printer_get_capabilities;
375   
376   g_object_class_install_property (object_class, 
377                                    PROP_STATUS,
378                                    g_param_spec_int ("status",
379                                                      "Status",
380                                                      "The status of the print backend",
381                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
382                                                      GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
383                                                      GTK_PRINT_BACKEND_STATUS_UNKNOWN,
384                                                      GTK_PARAM_READWRITE)); 
385
386   g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
387   
388   signals[PRINTER_LIST_CHANGED] =
389     g_signal_new (I_("printer-list-changed"),
390                   G_TYPE_FROM_CLASS (class),
391                   G_SIGNAL_RUN_LAST,
392                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
393                   NULL, NULL,
394                   g_cclosure_marshal_VOID__VOID,
395                   G_TYPE_NONE, 0);
396   signals[PRINTER_LIST_DONE] =
397     g_signal_new (I_("printer-list-done"),
398                     G_TYPE_FROM_CLASS (class),
399                     G_SIGNAL_RUN_LAST,
400                     G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
401                     NULL, NULL,
402                     g_cclosure_marshal_VOID__VOID,
403                     G_TYPE_NONE, 0);
404   signals[PRINTER_ADDED] =
405     g_signal_new (I_("printer-added"),
406                   G_TYPE_FROM_CLASS (class),
407                   G_SIGNAL_RUN_LAST,
408                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
409                   NULL, NULL,
410                   g_cclosure_marshal_VOID__OBJECT,
411                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
412   signals[PRINTER_REMOVED] =
413     g_signal_new (I_("printer-removed"),
414                   G_TYPE_FROM_CLASS (class),
415                   G_SIGNAL_RUN_LAST,
416                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
417                   NULL, NULL,
418                   g_cclosure_marshal_VOID__OBJECT,
419                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
420   signals[PRINTER_STATUS_CHANGED] =
421     g_signal_new (I_("printer-status-changed"),
422                   G_TYPE_FROM_CLASS (class),
423                   G_SIGNAL_RUN_LAST,
424                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
425                   NULL, NULL,
426                   g_cclosure_marshal_VOID__OBJECT,
427                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
428 }
429
430 static void
431 gtk_print_backend_init (GtkPrintBackend *backend)
432 {
433   GtkPrintBackendPrivate *priv;
434
435   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
436
437   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
438                                           (GDestroyNotify) g_free,
439                                           (GDestroyNotify) g_object_unref);
440 }
441
442 static void
443 gtk_print_backend_dispose (GObject *object)
444 {
445   GtkPrintBackend *backend;
446   GtkPrintBackendPrivate *priv;
447
448   backend = GTK_PRINT_BACKEND (object);
449   priv = backend->priv;
450
451   /* We unref the printers in dispose, not in finalize so that
452    * we can break refcount cycles with gtk_print_backend_destroy 
453    */
454   if (priv->printers)
455     {
456       g_hash_table_destroy (priv->printers);
457       priv->printers = NULL;
458     }
459
460   backend_parent_class->dispose (object);
461 }
462
463
464 static void
465 fallback_printer_request_details (GtkPrinter *printer)
466 {
467 }
468
469 static gboolean
470 fallback_printer_mark_conflicts (GtkPrinter          *printer,
471                                  GtkPrinterOptionSet *options)
472 {
473   return FALSE;
474 }
475
476 static void
477 fallback_printer_get_hard_margins (GtkPrinter *printer,
478                                    gdouble    *top,
479                                    gdouble    *bottom,
480                                    gdouble    *left,
481                                    gdouble    *right)
482 {
483   *top = 0;
484   *bottom = 0;
485   *left = 0;
486   *right = 0;
487 }
488
489 static GList *
490 fallback_printer_list_papers (GtkPrinter *printer)
491 {
492   return NULL;
493 }
494
495 static GtkPageSetup *
496 fallback_printer_get_default_page_size (GtkPrinter *printer)
497 {
498   return NULL;
499 }
500
501 static GtkPrintCapabilities
502 fallback_printer_get_capabilities (GtkPrinter *printer)
503 {
504   return 0;
505 }
506
507
508 static void
509 printer_hash_to_sorted_active_list (const gchar  *key,
510                                     gpointer      value,
511                                     GList       **out_list)
512 {
513   GtkPrinter *printer;
514
515   printer = GTK_PRINTER (value);
516
517   if (gtk_printer_get_name (printer) == NULL)
518     return;
519
520   if (!gtk_printer_is_active (printer))
521     return;
522
523   *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
524 }
525
526
527 void
528 gtk_print_backend_add_printer (GtkPrintBackend *backend,
529                                GtkPrinter      *printer)
530 {
531   GtkPrintBackendPrivate *priv;
532   
533   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
534
535   priv = backend->priv;
536
537   if (!priv->printers)
538     return;
539   
540   g_hash_table_insert (priv->printers,
541                        g_strdup (gtk_printer_get_name (printer)), 
542                        g_object_ref (printer));
543 }
544
545 void
546 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
547                                   GtkPrinter      *printer)
548 {
549   GtkPrintBackendPrivate *priv;
550   
551   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
552   priv = backend->priv;
553
554   if (!priv->printers)
555     return;
556   
557   g_hash_table_remove (priv->printers,
558                        gtk_printer_get_name (printer));
559 }
560
561 void
562 gtk_print_backend_set_list_done (GtkPrintBackend *backend)
563 {
564   if (!backend->priv->printer_list_done)
565     {
566       backend->priv->printer_list_done = TRUE;
567       g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
568     }
569 }
570
571
572 GList *
573 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
574 {
575   GtkPrintBackendPrivate *priv;
576   GList *result;
577   
578   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
579
580   priv = backend->priv;
581
582   result = NULL;
583   if (priv->printers != NULL)
584     g_hash_table_foreach (priv->printers,
585                           (GHFunc) printer_hash_to_sorted_active_list,
586                           &result);
587
588   if (!priv->printer_list_requested && priv->printers != NULL)
589     {
590       if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
591         GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
592       priv->printer_list_requested = TRUE;
593     }
594
595   return result;
596 }
597
598 gboolean
599 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
600 {
601   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
602
603   return print_backend->priv->printer_list_done;
604 }
605
606 GtkPrinter *
607 gtk_print_backend_find_printer (GtkPrintBackend *backend,
608                                 const gchar     *printer_name)
609 {
610   GtkPrintBackendPrivate *priv;
611   GtkPrinter *printer;
612   
613   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
614
615   priv = backend->priv;
616
617   if (priv->printers)
618     printer = g_hash_table_lookup (priv->printers, printer_name);
619   else
620     printer = NULL;
621
622   return printer;  
623 }
624
625 void
626 gtk_print_backend_print_stream (GtkPrintBackend        *backend,
627                                 GtkPrintJob            *job,
628                                 GIOChannel             *data_io,
629                                 GtkPrintJobCompleteFunc callback,
630                                 gpointer                user_data,
631                                 GDestroyNotify          dnotify)
632 {
633   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
634
635   GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
636                                                        job,
637                                                        data_io,
638                                                        callback,
639                                                        user_data,
640                                                        dnotify);
641 }
642
643 void
644 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
645 {
646   /* The lifecycle of print backends and printers are tied, such that
647    * the backend owns the printers, but the printers also ref the backend.
648    * This is so that if the app has a reference to a printer its backend
649    * will be around. However, this results in a cycle, which we break
650    * with this call, which causes the print backend to release its printers.
651    */
652   g_object_run_dispose (G_OBJECT (print_backend));
653 }
654
655
656 #define __GTK_PRINT_BACKEND_C__
657 #include "gtkaliasdef.c"