1 /* GTK - The GIMP Toolkit
2 * gtkprintbackend.h: Abstract printer backend interfaces
3 * Copyright (C) 2003, Red Hat, Inc.
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.
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.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
25 #include "gtkmodules.h"
26 #include "gtkmodulesprivate.h"
27 #include "gtkmarshalers.h"
28 #include "gtkprivate.h"
29 #include "gtkprintbackend.h"
32 static void gtk_print_backend_dispose (GObject *object);
33 static void gtk_print_backend_set_property (GObject *object,
37 static void gtk_print_backend_get_property (GObject *object,
42 struct _GtkPrintBackendPrivate
45 guint printer_list_requested : 1;
46 guint printer_list_done : 1;
47 GtkPrintBackendStatus status;
48 char **auth_info_required;
57 PRINTER_STATUS_CHANGED,
62 static guint signals[LAST_SIGNAL] = { 0 };
70 static GObjectClass *backend_parent_class;
73 gtk_print_backend_error_quark (void)
75 static GQuark quark = 0;
77 quark = g_quark_from_static_string ("gtk-print-backend-error-quark");
81 /*****************************************
82 * GtkPrintBackendModule modules *
83 *****************************************/
85 typedef struct _GtkPrintBackendModule GtkPrintBackendModule;
86 typedef struct _GtkPrintBackendModuleClass GtkPrintBackendModuleClass;
88 struct _GtkPrintBackendModule
90 GTypeModule parent_instance;
94 void (*init) (GTypeModule *module);
96 GtkPrintBackend* (*create) (void);
101 struct _GtkPrintBackendModuleClass
103 GTypeModuleClass parent_class;
106 G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE)
107 #define GTK_TYPE_PRINT_BACKEND_MODULE (_gtk_print_backend_module_get_type ())
108 #define GTK_PRINT_BACKEND_MODULE(module) (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_PRINT_BACKEND_MODULE, GtkPrintBackendModule))
110 static GSList *loaded_backends;
113 gtk_print_backend_module_load (GTypeModule *module)
115 GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
116 gpointer initp, exitp, createp;
118 pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
119 if (!pb_module->library)
121 g_warning ("%s", g_module_error());
125 /* extract symbols from the lib */
126 if (!g_module_symbol (pb_module->library, "pb_module_init",
128 !g_module_symbol (pb_module->library, "pb_module_exit",
130 !g_module_symbol (pb_module->library, "pb_module_create",
133 g_warning ("%s", g_module_error());
134 g_module_close (pb_module->library);
139 pb_module->init = initp;
140 pb_module->exit = exitp;
141 pb_module->create = createp;
143 /* call the printbackend's init function to let it */
144 /* setup anything it needs to set up. */
145 pb_module->init (module);
151 gtk_print_backend_module_unload (GTypeModule *module)
153 GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
157 g_module_close (pb_module->library);
158 pb_module->library = NULL;
160 pb_module->init = NULL;
161 pb_module->exit = NULL;
162 pb_module->create = NULL;
165 /* This only will ever be called if an error occurs during
169 gtk_print_backend_module_finalize (GObject *object)
171 GtkPrintBackendModule *module = GTK_PRINT_BACKEND_MODULE (object);
173 g_free (module->path);
175 G_OBJECT_CLASS (_gtk_print_backend_module_parent_class)->finalize (object);
179 _gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
181 GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
182 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
184 module_class->load = gtk_print_backend_module_load;
185 module_class->unload = gtk_print_backend_module_unload;
187 gobject_class->finalize = gtk_print_backend_module_finalize;
191 gtk_print_backend_set_property (GObject *object,
196 GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
197 GtkPrintBackendPrivate *priv = backend->priv;
202 priv->status = g_value_get_int (value);
205 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
211 gtk_print_backend_get_property (GObject *object,
216 GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
217 GtkPrintBackendPrivate *priv = backend->priv;
222 g_value_set_int (value, priv->status);
225 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231 _gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
235 static GtkPrintBackend *
236 _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
240 if (g_type_module_use (G_TYPE_MODULE (pb_module)))
242 pb = pb_module->create ();
243 g_type_module_unuse (G_TYPE_MODULE (pb_module));
249 static GtkPrintBackend *
250 _gtk_print_backend_create (const gchar *backend_name)
255 GtkPrintBackendModule *pb_module;
258 for (l = loaded_backends; l != NULL; l = l->next)
262 if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
263 return _gtk_print_backend_module_create (pb_module);
267 if (g_module_supported ())
269 full_name = g_strconcat ("printbackend-", backend_name, NULL);
270 module_path = _gtk_find_module (full_name, "printbackends");
275 pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);
277 g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
278 pb_module->path = g_strdup (module_path);
280 loaded_backends = g_slist_prepend (loaded_backends,
283 pb = _gtk_print_backend_module_create (pb_module);
285 /* Increase use-count so that we don't unload print backends.
286 * There is a problem with module unloading in the cups module,
287 * see cups_dispatch_watch_finalize for details.
289 g_type_module_use (G_TYPE_MODULE (pb_module));
292 g_free (module_path);
299 * gtk_print_backend_load_modules:
301 * Return value: (element-type GtkPrintBackend) (transfer container):
304 gtk_print_backend_load_modules (void)
307 GtkPrintBackend *backend;
311 GtkSettings *settings;
315 settings = gtk_settings_get_default ();
317 g_object_get (settings, "gtk-print-backends", &setting, NULL);
319 setting = g_strdup (GTK_PRINT_BACKENDS);
321 backends = g_strsplit (setting, ",", -1);
323 for (i = 0; backends[i]; i++)
325 g_strchug (backends[i]);
326 g_strchomp (backends[i]);
327 backend = _gtk_print_backend_create (backends[i]);
330 result = g_list_append (result, backend);
333 g_strfreev (backends);
339 /*****************************************
341 *****************************************/
343 G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
345 static void fallback_printer_request_details (GtkPrinter *printer);
346 static gboolean fallback_printer_mark_conflicts (GtkPrinter *printer,
347 GtkPrinterOptionSet *options);
348 static gboolean fallback_printer_get_hard_margins (GtkPrinter *printer,
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 static void request_password (GtkPrintBackend *backend,
357 gpointer auth_info_required,
358 gpointer auth_info_default,
359 gpointer auth_info_display,
360 gpointer auth_info_visible,
361 const gchar *prompt);
364 gtk_print_backend_class_init (GtkPrintBackendClass *class)
366 GObjectClass *object_class;
367 object_class = (GObjectClass *) class;
369 backend_parent_class = g_type_class_peek_parent (class);
371 object_class->dispose = gtk_print_backend_dispose;
372 object_class->set_property = gtk_print_backend_set_property;
373 object_class->get_property = gtk_print_backend_get_property;
375 class->printer_request_details = fallback_printer_request_details;
376 class->printer_mark_conflicts = fallback_printer_mark_conflicts;
377 class->printer_get_hard_margins = fallback_printer_get_hard_margins;
378 class->printer_list_papers = fallback_printer_list_papers;
379 class->printer_get_default_page_size = fallback_printer_get_default_page_size;
380 class->printer_get_capabilities = fallback_printer_get_capabilities;
381 class->request_password = request_password;
383 g_object_class_install_property (object_class,
385 g_param_spec_int ("status",
387 "The status of the print backend",
388 GTK_PRINT_BACKEND_STATUS_UNKNOWN,
389 GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
390 GTK_PRINT_BACKEND_STATUS_UNKNOWN,
391 GTK_PARAM_READWRITE));
393 g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
395 signals[PRINTER_LIST_CHANGED] =
396 g_signal_new (I_("printer-list-changed"),
397 G_TYPE_FROM_CLASS (class),
399 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
401 g_cclosure_marshal_VOID__VOID,
403 signals[PRINTER_LIST_DONE] =
404 g_signal_new (I_("printer-list-done"),
405 G_TYPE_FROM_CLASS (class),
407 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
409 g_cclosure_marshal_VOID__VOID,
411 signals[PRINTER_ADDED] =
412 g_signal_new (I_("printer-added"),
413 G_TYPE_FROM_CLASS (class),
415 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
417 g_cclosure_marshal_VOID__OBJECT,
418 G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
419 signals[PRINTER_REMOVED] =
420 g_signal_new (I_("printer-removed"),
421 G_TYPE_FROM_CLASS (class),
423 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
425 g_cclosure_marshal_VOID__OBJECT,
426 G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
427 signals[PRINTER_STATUS_CHANGED] =
428 g_signal_new (I_("printer-status-changed"),
429 G_TYPE_FROM_CLASS (class),
431 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
433 g_cclosure_marshal_VOID__OBJECT,
434 G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
435 signals[REQUEST_PASSWORD] =
436 g_signal_new (I_("request-password"),
437 G_TYPE_FROM_CLASS (class),
439 G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
441 _gtk_marshal_VOID__POINTER_POINTER_POINTER_POINTER_STRING,
442 G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING);
446 gtk_print_backend_init (GtkPrintBackend *backend)
448 GtkPrintBackendPrivate *priv;
450 priv = backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend,
451 GTK_TYPE_PRINT_BACKEND,
452 GtkPrintBackendPrivate);
454 priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal,
455 (GDestroyNotify) g_free,
456 (GDestroyNotify) g_object_unref);
457 priv->auth_info_required = NULL;
458 priv->auth_info = NULL;
462 gtk_print_backend_dispose (GObject *object)
464 GtkPrintBackend *backend;
465 GtkPrintBackendPrivate *priv;
467 backend = GTK_PRINT_BACKEND (object);
468 priv = backend->priv;
470 /* We unref the printers in dispose, not in finalize so that
471 * we can break refcount cycles with gtk_print_backend_destroy
475 g_hash_table_destroy (priv->printers);
476 priv->printers = NULL;
479 backend_parent_class->dispose (object);
484 fallback_printer_request_details (GtkPrinter *printer)
489 fallback_printer_mark_conflicts (GtkPrinter *printer,
490 GtkPrinterOptionSet *options)
496 fallback_printer_get_hard_margins (GtkPrinter *printer,
506 fallback_printer_list_papers (GtkPrinter *printer)
511 static GtkPageSetup *
512 fallback_printer_get_default_page_size (GtkPrinter *printer)
517 static GtkPrintCapabilities
518 fallback_printer_get_capabilities (GtkPrinter *printer)
525 printer_hash_to_sorted_active_list (const gchar *key,
531 printer = GTK_PRINTER (value);
533 if (gtk_printer_get_name (printer) == NULL)
536 if (!gtk_printer_is_active (printer))
539 *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
544 gtk_print_backend_add_printer (GtkPrintBackend *backend,
547 GtkPrintBackendPrivate *priv;
549 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
551 priv = backend->priv;
556 g_hash_table_insert (priv->printers,
557 g_strdup (gtk_printer_get_name (printer)),
558 g_object_ref (printer));
562 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
565 GtkPrintBackendPrivate *priv;
567 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
568 priv = backend->priv;
573 g_hash_table_remove (priv->printers,
574 gtk_printer_get_name (printer));
578 gtk_print_backend_set_list_done (GtkPrintBackend *backend)
580 if (!backend->priv->printer_list_done)
582 backend->priv->printer_list_done = TRUE;
583 g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
589 * gtk_print_backend_get_printer_list:
591 * Returns the current list of printers.
593 * Return value: (element-type GtkPrinter) (transfer container):
594 * A list of #GtkPrinter objects. The list should be freed
595 * with g_list_free().
598 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
600 GtkPrintBackendPrivate *priv;
603 g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
605 priv = backend->priv;
608 if (priv->printers != NULL)
609 g_hash_table_foreach (priv->printers,
610 (GHFunc) printer_hash_to_sorted_active_list,
613 if (!priv->printer_list_requested && priv->printers != NULL)
615 if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
616 GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
617 priv->printer_list_requested = TRUE;
624 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
626 g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
628 return print_backend->priv->printer_list_done;
632 gtk_print_backend_find_printer (GtkPrintBackend *backend,
633 const gchar *printer_name)
635 GtkPrintBackendPrivate *priv;
638 g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
640 priv = backend->priv;
643 printer = g_hash_table_lookup (priv->printers, printer_name);
651 gtk_print_backend_print_stream (GtkPrintBackend *backend,
654 GtkPrintJobCompleteFunc callback,
656 GDestroyNotify dnotify)
658 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
660 GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
669 gtk_print_backend_set_password (GtkPrintBackend *backend,
670 gchar **auth_info_required,
673 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
675 if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
676 GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, auth_info_required, auth_info);
680 store_entry (GtkEntry *entry,
683 gchar **data = (gchar **) user_data;
687 memset (*data, 0, strlen (*data));
691 *data = g_strdup (gtk_entry_get_text (entry));
695 password_dialog_response (GtkWidget *dialog,
697 GtkPrintBackend *backend)
699 GtkPrintBackendPrivate *priv = backend->priv;
702 if (response_id == GTK_RESPONSE_OK)
703 gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info);
705 gtk_print_backend_set_password (backend, priv->auth_info_required, NULL);
707 for (i = 0; i < g_strv_length (priv->auth_info_required); i++)
708 if (priv->auth_info[i] != NULL)
710 memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
711 g_free (priv->auth_info[i]);
712 priv->auth_info[i] = NULL;
714 g_free (priv->auth_info);
715 priv->auth_info = NULL;
717 g_strfreev (priv->auth_info_required);
719 gtk_widget_destroy (dialog);
721 g_object_unref (backend);
725 request_password (GtkPrintBackend *backend,
726 gpointer auth_info_required,
727 gpointer auth_info_default,
728 gpointer auth_info_display,
729 gpointer auth_info_visible,
732 GtkPrintBackendPrivate *priv = backend->priv;
733 GtkWidget *dialog, *box, *main_box, *label, *icon, *vbox, *entry;
734 GtkWidget *focus = NULL;
735 GtkWidget *content_area;
739 gchar **ai_required = (gchar **) auth_info_required;
740 gchar **ai_default = (gchar **) auth_info_default;
741 gchar **ai_display = (gchar **) auth_info_display;
742 gboolean *ai_visible = (gboolean *) auth_info_visible;
744 priv->auth_info_required = g_strdupv (ai_required);
745 length = g_strv_length (ai_required);
746 priv->auth_info = g_new0 (gchar *, length);
748 dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL,
749 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
750 GTK_STOCK_OK, GTK_RESPONSE_OK,
753 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
755 main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
758 icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
759 gtk_widget_set_halign (icon, GTK_ALIGN_CENTER);
760 gtk_widget_set_valign (icon, GTK_ALIGN_START);
761 g_object_set (icon, "margin", 6, NULL);
764 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
765 gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);
768 label = gtk_label_new (NULL);
769 markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", prompt);
770 gtk_label_set_markup (GTK_LABEL (label), markup);
771 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
772 gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
777 content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
778 gtk_box_pack_start (GTK_BOX (content_area), main_box, TRUE, FALSE, 0);
780 gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
781 gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
783 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
786 for (i = 0; i < length; i++)
788 priv->auth_info[i] = g_strdup (ai_default[i]);
789 if (ai_display[i] != NULL)
791 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
792 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
794 label = gtk_label_new (ai_display[i]);
795 gtk_widget_set_halign (label, GTK_ALIGN_START);
796 gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
798 entry = gtk_entry_new ();
801 if (ai_default[i] != NULL)
802 gtk_entry_set_text (GTK_ENTRY (entry), ai_default[i]);
804 gtk_entry_set_visibility (GTK_ENTRY (entry), ai_visible[i]);
805 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
807 gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, TRUE, 6);
809 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
810 gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0);
812 g_signal_connect (entry, "changed",
813 G_CALLBACK (store_entry), &(priv->auth_info[i]));
819 gtk_widget_grab_focus (focus);
823 g_object_ref (backend);
824 g_signal_connect (G_OBJECT (dialog), "response",
825 G_CALLBACK (password_dialog_response), backend);
827 gtk_widget_show_all (dialog);
831 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
833 /* The lifecycle of print backends and printers are tied, such that
834 * the backend owns the printers, but the printers also ref the backend.
835 * This is so that if the app has a reference to a printer its backend
836 * will be around. However, this results in a cycle, which we break
837 * with this call, which causes the print backend to release its printers.
839 g_object_run_dispose (G_OBJECT (print_backend));