]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintbackend.c
Added new symbols
[~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       
232       g_free (module_path);
233     }
234
235   return pb;
236
237   return NULL;
238 }
239
240 static void
241 gtk_print_backend_initialize (void)
242 {
243   static gboolean initialized = FALSE;
244
245   if (!initialized)
246     {
247       gtk_settings_install_property (g_param_spec_string ("gtk-print-backends",
248                                                           P_("Default print backend"),
249                                                           P_("List of the GtkPrintBackend backends to use by default"),
250                                                           GTK_PRINT_BACKENDS,
251                                                           GTK_PARAM_READWRITE));
252
253       initialized = TRUE;
254     }
255 }
256
257
258
259 GList *
260 gtk_print_backend_load_modules ()
261 {
262   GList *result;
263   GtkPrintBackend *backend;
264   gchar *setting;
265   gchar **backends;
266   gint i;
267   GtkSettings *settings;
268
269   result = NULL;
270
271   gtk_print_backend_initialize ();
272   
273   settings = gtk_settings_get_default ();
274
275   g_object_get (settings, "gtk-print-backends", &setting, NULL);
276
277   backends = g_strsplit (setting, ",", -1);
278
279   for (i = 0; backends[i]; i++)
280     {
281       g_strchug (backends[i]);
282       g_strchomp (backends[i]);
283       backend = _gtk_print_backend_create (backends[i]);
284       
285       if (backend)
286         result = g_list_append (result, backend);
287     }
288
289   g_strfreev (backends);
290   g_free (setting);
291
292   return result;
293 }
294
295 /*****************************************
296  *             GtkPrintBackend           *
297  *****************************************/
298
299 G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT);
300
301 static void
302 gtk_print_backend_class_init (GtkPrintBackendClass *class)
303 {
304   GObjectClass *object_class;
305   object_class = (GObjectClass *) class;
306
307   backend_parent_class = g_type_class_peek_parent (class);
308   
309   object_class->dispose = gtk_print_backend_dispose;
310
311   g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
312
313   
314   signals[PRINTER_LIST_CHANGED] =
315     g_signal_new ("printer-list-changed",
316                   G_TYPE_FROM_CLASS (class),
317                   G_SIGNAL_RUN_LAST,
318                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
319                   NULL, NULL,
320                   g_cclosure_marshal_VOID__VOID,
321                   G_TYPE_NONE, 0);
322   signals[PRINTER_LIST_DONE] =
323       g_signal_new ("printer-list-done",
324                     G_TYPE_FROM_CLASS (class),
325                     G_SIGNAL_RUN_LAST,
326                     G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
327                     NULL, NULL,
328                     g_cclosure_marshal_VOID__VOID,
329                     G_TYPE_NONE, 0);
330   signals[PRINTER_ADDED] =
331     g_signal_new ("printer-added",
332                   G_TYPE_FROM_CLASS (class),
333                   G_SIGNAL_RUN_LAST,
334                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
335                   NULL, NULL,
336                   g_cclosure_marshal_VOID__OBJECT,
337                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
338   signals[PRINTER_REMOVED] =
339     g_signal_new ("printer-removed",
340                   G_TYPE_FROM_CLASS (class),
341                   G_SIGNAL_RUN_LAST,
342                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
343                   NULL, NULL,
344                   g_cclosure_marshal_VOID__OBJECT,
345                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
346   signals[PRINTER_STATUS_CHANGED] =
347     g_signal_new ("printer-status-changed",
348                   G_TYPE_FROM_CLASS (class),
349                   G_SIGNAL_RUN_LAST,
350                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
351                   NULL, NULL,
352                   g_cclosure_marshal_VOID__OBJECT,
353                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
354 }
355
356 static void
357 gtk_print_backend_init (GtkPrintBackend *backend)
358 {
359   GtkPrintBackendPrivate *priv;
360
361   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
362
363   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
364                                           (GDestroyNotify) g_free,
365                                           (GDestroyNotify) g_object_unref);
366 }
367
368 static void
369 gtk_print_backend_dispose (GObject *object)
370 {
371   GtkPrintBackend *backend;
372   GtkPrintBackendPrivate *priv;
373
374   backend = GTK_PRINT_BACKEND (object);
375   priv = backend->priv;
376
377   /* We unref the printers in dispose, not in finalize so that
378      we can break refcount cycles with gtk_print_backend_destroy */
379   if (priv->printers)
380     {
381       g_hash_table_destroy (priv->printers);
382       priv->printers = NULL;
383     }
384
385   backend_parent_class->dispose (object);
386 }
387
388
389 static void
390 printer_hash_to_sorted_active_list (const gchar *key,
391                                     gpointer value,
392                                     GList **out_list)
393 {
394   GtkPrinter *printer;
395
396   printer = GTK_PRINTER (value);
397
398   if (gtk_printer_get_name (printer) == NULL)
399     return;
400
401   if (!gtk_printer_is_active (printer))
402     return;
403
404   *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
405 }
406
407
408 void
409 gtk_print_backend_add_printer (GtkPrintBackend *backend,
410                                GtkPrinter *printer)
411 {
412   GtkPrintBackendPrivate *priv;
413   
414   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
415
416   priv = backend->priv;
417
418   if (!priv->printers)
419     return;
420   
421   g_hash_table_insert (priv->printers,
422                        g_strdup (gtk_printer_get_name (printer)), 
423                        g_object_ref (printer));
424 }
425
426 void
427 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
428                                   GtkPrinter *printer)
429 {
430   GtkPrintBackendPrivate *priv;
431   
432   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
433   priv = backend->priv;
434
435   if (!priv->printers)
436     return;
437   
438   g_hash_table_remove (priv->printers,
439                        gtk_printer_get_name (printer));
440 }
441
442 void
443 gtk_print_backend_set_list_done (GtkPrintBackend *backend)
444 {
445   if (!backend->priv->printer_list_done)
446     {
447       backend->priv->printer_list_done = TRUE;
448       g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
449     }
450 }
451
452
453 GList *
454 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
455 {
456   GtkPrintBackendPrivate *priv;
457   GList *result;
458   
459   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
460
461   priv = backend->priv;
462
463   result = NULL;
464   if (priv->printers != NULL)
465     g_hash_table_foreach (priv->printers,
466                           (GHFunc) printer_hash_to_sorted_active_list,
467                           &result);
468
469   if (!priv->printer_list_requested && priv->printers != NULL)
470     {
471       if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
472         GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
473       priv->printer_list_requested = TRUE;
474     }
475   
476   return result;;
477 }
478
479 gboolean
480 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
481 {
482   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
483
484   return print_backend->priv->printer_list_done;
485 }
486
487 GtkPrinter *
488 gtk_print_backend_find_printer (GtkPrintBackend *backend,
489                                 const gchar *printer_name)
490 {
491   GtkPrintBackendPrivate *priv;
492   GtkPrinter *printer;
493   
494   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
495
496   priv = backend->priv;
497
498   if (priv->printers)
499     printer = g_hash_table_lookup (priv->printers, printer_name);
500   else
501     printer = NULL;
502
503   return printer;  
504 }
505
506 void
507 gtk_print_backend_print_stream (GtkPrintBackend *backend,
508                                 GtkPrintJob *job,
509                                 gint data_fd,
510                                 GtkPrintJobCompleteFunc callback,
511                                 gpointer user_data,
512                                 GDestroyNotify dnotify)
513 {
514   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
515
516   GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
517                                                        job,
518                                                        data_fd,
519                                                        callback,
520                                                        user_data,
521                                                        dnotify);
522 }
523
524 static gboolean
525 unref_at_idle_cb (gpointer data)
526 {
527   g_object_unref (data);
528   return FALSE;
529 }
530
531 void
532 gtk_print_backend_unref_at_idle (GtkPrintBackend *print_backend)
533 {
534   g_idle_add (unref_at_idle_cb, print_backend);
535 }
536
537 void
538 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
539 {
540   /* The lifecycle of print backends and printers are tied, such that
541      the backend owns the printers, but the printers also ref the backend.
542      This is so that if the app has a reference to a printer its backend
543      will be around. However, this results in a cycle, which we break
544      with this call, which causes the print backend to release its printers.
545   */
546   g_object_run_dispose (G_OBJECT (print_backend));
547 }
548
549 #define __GTK_PRINT_BACKEND_C__
550 #include "gtkaliasdef.c"