]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintbackend.c
Add gtk_print_unix_dialog_set_manual_capabilities that controls what
[~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                 fallback_printer_request_details  (GtkPrinter          *printer);
307 static gboolean             fallback_printer_mark_conflicts   (GtkPrinter          *printer,
308                                                                GtkPrinterOptionSet *options);
309 static void                 fallback_printer_get_hard_margins (GtkPrinter          *printer,
310                                                                double              *top,
311                                                                double              *bottom,
312                                                                double              *left,
313                                                                double              *right);
314 static GList *              fallback_printer_list_papers      (GtkPrinter          *printer);
315 static GtkPrintCapabilities fallback_printer_get_capabilities (GtkPrinter          *printer);
316   
317 static void
318 gtk_print_backend_class_init (GtkPrintBackendClass *class)
319 {
320   GObjectClass *object_class;
321   object_class = (GObjectClass *) class;
322
323   backend_parent_class = g_type_class_peek_parent (class);
324   
325   object_class->dispose = gtk_print_backend_dispose;
326
327   class->printer_request_details = fallback_printer_request_details;
328   class->printer_mark_conflicts = fallback_printer_mark_conflicts;
329   class->printer_get_hard_margins = fallback_printer_get_hard_margins;
330   class->printer_list_papers = fallback_printer_list_papers;
331   class->printer_get_capabilities = fallback_printer_get_capabilities;
332   
333   g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
334   
335   signals[PRINTER_LIST_CHANGED] =
336     g_signal_new ("printer-list-changed",
337                   G_TYPE_FROM_CLASS (class),
338                   G_SIGNAL_RUN_LAST,
339                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
340                   NULL, NULL,
341                   g_cclosure_marshal_VOID__VOID,
342                   G_TYPE_NONE, 0);
343   signals[PRINTER_LIST_DONE] =
344       g_signal_new ("printer-list-done",
345                     G_TYPE_FROM_CLASS (class),
346                     G_SIGNAL_RUN_LAST,
347                     G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
348                     NULL, NULL,
349                     g_cclosure_marshal_VOID__VOID,
350                     G_TYPE_NONE, 0);
351   signals[PRINTER_ADDED] =
352     g_signal_new ("printer-added",
353                   G_TYPE_FROM_CLASS (class),
354                   G_SIGNAL_RUN_LAST,
355                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
356                   NULL, NULL,
357                   g_cclosure_marshal_VOID__OBJECT,
358                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
359   signals[PRINTER_REMOVED] =
360     g_signal_new ("printer-removed",
361                   G_TYPE_FROM_CLASS (class),
362                   G_SIGNAL_RUN_LAST,
363                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
364                   NULL, NULL,
365                   g_cclosure_marshal_VOID__OBJECT,
366                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
367   signals[PRINTER_STATUS_CHANGED] =
368     g_signal_new ("printer-status-changed",
369                   G_TYPE_FROM_CLASS (class),
370                   G_SIGNAL_RUN_LAST,
371                   G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
372                   NULL, NULL,
373                   g_cclosure_marshal_VOID__OBJECT,
374                   G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
375 }
376
377 static void
378 gtk_print_backend_init (GtkPrintBackend *backend)
379 {
380   GtkPrintBackendPrivate *priv;
381
382   priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
383
384   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
385                                           (GDestroyNotify) g_free,
386                                           (GDestroyNotify) g_object_unref);
387 }
388
389 static void
390 gtk_print_backend_dispose (GObject *object)
391 {
392   GtkPrintBackend *backend;
393   GtkPrintBackendPrivate *priv;
394
395   backend = GTK_PRINT_BACKEND (object);
396   priv = backend->priv;
397
398   /* We unref the printers in dispose, not in finalize so that
399      we can break refcount cycles with gtk_print_backend_destroy */
400   if (priv->printers)
401     {
402       g_hash_table_destroy (priv->printers);
403       priv->printers = NULL;
404     }
405
406   backend_parent_class->dispose (object);
407 }
408
409
410 static void
411 fallback_printer_request_details (GtkPrinter *printer)
412 {
413 }
414
415 static gboolean
416 fallback_printer_mark_conflicts (GtkPrinter *printer,
417                                  GtkPrinterOptionSet *options)
418 {
419   return FALSE;
420 }
421
422 static void
423 fallback_printer_get_hard_margins (GtkPrinter *printer,
424                                    double *top,
425                                    double *bottom,
426                                    double *left,
427                                    double *right)
428 {
429   *top = 0;
430   *bottom = 0;
431   *left = 0;
432   *right = 0;
433 }
434
435 static GList *
436 fallback_printer_list_papers (GtkPrinter *printer)
437 {
438   return NULL;
439 }
440
441 static GtkPrintCapabilities
442 fallback_printer_get_capabilities (GtkPrinter *printer)
443 {
444   return 0;
445 }
446
447
448 static void
449 printer_hash_to_sorted_active_list (const gchar *key,
450                                     gpointer value,
451                                     GList **out_list)
452 {
453   GtkPrinter *printer;
454
455   printer = GTK_PRINTER (value);
456
457   if (gtk_printer_get_name (printer) == NULL)
458     return;
459
460   if (!gtk_printer_is_active (printer))
461     return;
462
463   *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
464 }
465
466
467 void
468 gtk_print_backend_add_printer (GtkPrintBackend *backend,
469                                GtkPrinter *printer)
470 {
471   GtkPrintBackendPrivate *priv;
472   
473   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
474
475   priv = backend->priv;
476
477   if (!priv->printers)
478     return;
479   
480   g_hash_table_insert (priv->printers,
481                        g_strdup (gtk_printer_get_name (printer)), 
482                        g_object_ref (printer));
483 }
484
485 void
486 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
487                                   GtkPrinter *printer)
488 {
489   GtkPrintBackendPrivate *priv;
490   
491   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
492   priv = backend->priv;
493
494   if (!priv->printers)
495     return;
496   
497   g_hash_table_remove (priv->printers,
498                        gtk_printer_get_name (printer));
499 }
500
501 void
502 gtk_print_backend_set_list_done (GtkPrintBackend *backend)
503 {
504   if (!backend->priv->printer_list_done)
505     {
506       backend->priv->printer_list_done = TRUE;
507       g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
508     }
509 }
510
511
512 GList *
513 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
514 {
515   GtkPrintBackendPrivate *priv;
516   GList *result;
517   
518   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
519
520   priv = backend->priv;
521
522   result = NULL;
523   if (priv->printers != NULL)
524     g_hash_table_foreach (priv->printers,
525                           (GHFunc) printer_hash_to_sorted_active_list,
526                           &result);
527
528   if (!priv->printer_list_requested && priv->printers != NULL)
529     {
530       if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
531         GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
532       priv->printer_list_requested = TRUE;
533     }
534   
535   return result;;
536 }
537
538 gboolean
539 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
540 {
541   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
542
543   return print_backend->priv->printer_list_done;
544 }
545
546 GtkPrinter *
547 gtk_print_backend_find_printer (GtkPrintBackend *backend,
548                                 const gchar *printer_name)
549 {
550   GtkPrintBackendPrivate *priv;
551   GtkPrinter *printer;
552   
553   g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
554
555   priv = backend->priv;
556
557   if (priv->printers)
558     printer = g_hash_table_lookup (priv->printers, printer_name);
559   else
560     printer = NULL;
561
562   return printer;  
563 }
564
565 void
566 gtk_print_backend_print_stream (GtkPrintBackend *backend,
567                                 GtkPrintJob *job,
568                                 gint data_fd,
569                                 GtkPrintJobCompleteFunc callback,
570                                 gpointer user_data,
571                                 GDestroyNotify dnotify)
572 {
573   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
574
575   GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
576                                                        job,
577                                                        data_fd,
578                                                        callback,
579                                                        user_data,
580                                                        dnotify);
581 }
582
583 void
584 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
585 {
586   /* The lifecycle of print backends and printers are tied, such that
587      the backend owns the printers, but the printers also ref the backend.
588      This is so that if the app has a reference to a printer its backend
589      will be around. However, this results in a cycle, which we break
590      with this call, which causes the print backend to release its printers.
591   */
592   g_object_run_dispose (G_OBJECT (print_backend));
593 }
594
595 #define __GTK_PRINT_BACKEND_C__
596 #include "gtkaliasdef.c"