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