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