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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
27 #include "gtkmodules.h"
28 #include "gtkmarshalers.h"
29 #include "gtkprivate.h"
30 #include "gtkprintbackend.h"
31 #include "gtkprinter-private.h"
34 #define GTK_PRINT_BACKEND_GET_PRIVATE(o) \
35 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendPrivate))
37 static void gtk_print_backend_dispose (GObject *object);
38 static void gtk_print_backend_set_property (GObject *object,
42 static void gtk_print_backend_get_property (GObject *object,
47 struct _GtkPrintBackendPrivate
50 guint printer_list_requested : 1;
51 guint printer_list_done : 1;
52 GtkPrintBackendStatus status;
63 PRINTER_STATUS_CHANGED,
68 static guint signals[LAST_SIGNAL] = { 0 };
76 static GObjectClass *backend_parent_class;
79 gtk_print_backend_error_quark (void)
81 static GQuark quark = 0;
83 quark = g_quark_from_static_string ("gtk-print-backend-error-quark");
87 /*****************************************
88 * GtkPrintBackendModule modules *
89 *****************************************/
91 typedef struct _GtkPrintBackendModule GtkPrintBackendModule;
92 typedef struct _GtkPrintBackendModuleClass GtkPrintBackendModuleClass;
94 struct _GtkPrintBackendModule
96 GTypeModule parent_instance;
100 void (*init) (GTypeModule *module);
102 GtkPrintBackend* (*create) (void);
107 struct _GtkPrintBackendModuleClass
109 GTypeModuleClass parent_class;
112 G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE)
113 #define GTK_TYPE_PRINT_BACKEND_MODULE (_gtk_print_backend_module_get_type ())
114 #define GTK_PRINT_BACKEND_MODULE(module) (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_PRINT_BACKEND_MODULE, GtkPrintBackendModule))
116 static GSList *loaded_backends;
119 gtk_print_backend_module_load (GTypeModule *module)
121 GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
122 gpointer initp, exitp, createp;
124 pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
125 if (!pb_module->library)
127 g_warning ("%s", g_module_error());
131 /* extract symbols from the lib */
132 if (!g_module_symbol (pb_module->library, "pb_module_init",
134 !g_module_symbol (pb_module->library, "pb_module_exit",
136 !g_module_symbol (pb_module->library, "pb_module_create",
139 g_warning ("%s", g_module_error());
140 g_module_close (pb_module->library);
145 pb_module->init = initp;
146 pb_module->exit = exitp;
147 pb_module->create = createp;
149 /* call the printbackend's init function to let it */
150 /* setup anything it needs to set up. */
151 pb_module->init (module);
157 gtk_print_backend_module_unload (GTypeModule *module)
159 GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
163 g_module_close (pb_module->library);
164 pb_module->library = NULL;
166 pb_module->init = NULL;
167 pb_module->exit = NULL;
168 pb_module->create = NULL;
171 /* This only will ever be called if an error occurs during
175 gtk_print_backend_module_finalize (GObject *object)
177 GtkPrintBackendModule *module = GTK_PRINT_BACKEND_MODULE (object);
179 g_free (module->path);
181 G_OBJECT_CLASS (_gtk_print_backend_module_parent_class)->finalize (object);
185 _gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
187 GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
188 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
190 module_class->load = gtk_print_backend_module_load;
191 module_class->unload = gtk_print_backend_module_unload;
193 gobject_class->finalize = gtk_print_backend_module_finalize;
197 gtk_print_backend_set_property (GObject *object,
202 GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
203 GtkPrintBackendPrivate *priv;
205 priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend);
210 priv->status = g_value_get_int (value);
213 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219 gtk_print_backend_get_property (GObject *object,
224 GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
225 GtkPrintBackendPrivate *priv;
227 priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend);
232 g_value_set_int (value, priv->status);
235 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
241 _gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
245 static GtkPrintBackend *
246 _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
250 if (g_type_module_use (G_TYPE_MODULE (pb_module)))
252 pb = pb_module->create ();
253 g_type_module_unuse (G_TYPE_MODULE (pb_module));
259 static GtkPrintBackend *
260 _gtk_print_backend_create (const gchar *backend_name)
265 GtkPrintBackendModule *pb_module;
268 for (l = loaded_backends; l != NULL; l = l->next)
272 if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
273 return _gtk_print_backend_module_create (pb_module);
277 if (g_module_supported ())
279 full_name = g_strconcat ("printbackend-", backend_name, NULL);
280 module_path = _gtk_find_module (full_name, "printbackends");
285 pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);
287 g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
288 pb_module->path = g_strdup (module_path);
290 loaded_backends = g_slist_prepend (loaded_backends,
293 pb = _gtk_print_backend_module_create (pb_module);
295 /* Increase use-count so that we don't unload print backends.
296 * There is a problem with module unloading in the cups module,
297 * see cups_dispatch_watch_finalize for details.
299 g_type_module_use (G_TYPE_MODULE (pb_module));
302 g_free (module_path);
309 gtk_print_backend_load_modules (void)
312 GtkPrintBackend *backend;
316 GtkSettings *settings;
320 settings = gtk_settings_get_default ();
322 g_object_get (settings, "gtk-print-backends", &setting, NULL);
324 setting = g_strdup (GTK_PRINT_BACKENDS);
326 backends = g_strsplit (setting, ",", -1);
328 for (i = 0; backends[i]; i++)
330 g_strchug (backends[i]);
331 g_strchomp (backends[i]);
332 backend = _gtk_print_backend_create (backends[i]);
335 result = g_list_append (result, backend);
338 g_strfreev (backends);
344 /*****************************************
346 *****************************************/
348 G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
350 static void fallback_printer_request_details (GtkPrinter *printer);
351 static gboolean fallback_printer_mark_conflicts (GtkPrinter *printer,
352 GtkPrinterOptionSet *options);
353 static void fallback_printer_get_hard_margins (GtkPrinter *printer,
358 static GList * fallback_printer_list_papers (GtkPrinter *printer);
359 static GtkPageSetup * fallback_printer_get_default_page_size (GtkPrinter *printer);
360 static GtkPrintCapabilities fallback_printer_get_capabilities (GtkPrinter *printer);
361 static void request_password (GtkPrintBackend *backend,
362 const gchar *hostname,
363 const gchar *username,
364 const gchar *prompt);
367 gtk_print_backend_class_init (GtkPrintBackendClass *class)
369 GObjectClass *object_class;
370 object_class = (GObjectClass *) class;
372 backend_parent_class = g_type_class_peek_parent (class);
374 object_class->dispose = gtk_print_backend_dispose;
375 object_class->set_property = gtk_print_backend_set_property;
376 object_class->get_property = gtk_print_backend_get_property;
378 class->printer_request_details = fallback_printer_request_details;
379 class->printer_mark_conflicts = fallback_printer_mark_conflicts;
380 class->printer_get_hard_margins = fallback_printer_get_hard_margins;
381 class->printer_list_papers = fallback_printer_list_papers;
382 class->printer_get_default_page_size = fallback_printer_get_default_page_size;
383 class->printer_get_capabilities = fallback_printer_get_capabilities;
384 class->request_password = request_password;
386 g_object_class_install_property (object_class,
388 g_param_spec_int ("status",
390 "The status of the print backend",
391 GTK_PRINT_BACKEND_STATUS_UNKNOWN,
392 GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
393 GTK_PRINT_BACKEND_STATUS_UNKNOWN,
394 GTK_PARAM_READWRITE));
396 g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
398 signals[PRINTER_LIST_CHANGED] =
399 g_signal_new (I_("printer-list-changed"),
400 G_TYPE_FROM_CLASS (class),
402 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed),
404 g_cclosure_marshal_VOID__VOID,
406 signals[PRINTER_LIST_DONE] =
407 g_signal_new (I_("printer-list-done"),
408 G_TYPE_FROM_CLASS (class),
410 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done),
412 g_cclosure_marshal_VOID__VOID,
414 signals[PRINTER_ADDED] =
415 g_signal_new (I_("printer-added"),
416 G_TYPE_FROM_CLASS (class),
418 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added),
420 g_cclosure_marshal_VOID__OBJECT,
421 G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
422 signals[PRINTER_REMOVED] =
423 g_signal_new (I_("printer-removed"),
424 G_TYPE_FROM_CLASS (class),
426 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed),
428 g_cclosure_marshal_VOID__OBJECT,
429 G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
430 signals[PRINTER_STATUS_CHANGED] =
431 g_signal_new (I_("printer-status-changed"),
432 G_TYPE_FROM_CLASS (class),
434 G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed),
436 g_cclosure_marshal_VOID__OBJECT,
437 G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
438 signals[REQUEST_PASSWORD] =
439 g_signal_new (I_("request-password"),
440 G_TYPE_FROM_CLASS (class),
442 G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
444 _gtk_marshal_VOID__STRING_STRING_STRING,
445 G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
449 gtk_print_backend_init (GtkPrintBackend *backend)
451 GtkPrintBackendPrivate *priv;
453 priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend);
455 priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal,
456 (GDestroyNotify) g_free,
457 (GDestroyNotify) g_object_unref);
458 priv->hostname = NULL;
459 priv->username = NULL;
460 priv->password = NULL;
464 gtk_print_backend_dispose (GObject *object)
466 GtkPrintBackend *backend;
467 GtkPrintBackendPrivate *priv;
469 backend = GTK_PRINT_BACKEND (object);
470 priv = backend->priv;
472 /* We unref the printers in dispose, not in finalize so that
473 * we can break refcount cycles with gtk_print_backend_destroy
477 g_hash_table_destroy (priv->printers);
478 priv->printers = NULL;
481 backend_parent_class->dispose (object);
486 fallback_printer_request_details (GtkPrinter *printer)
491 fallback_printer_mark_conflicts (GtkPrinter *printer,
492 GtkPrinterOptionSet *options)
498 fallback_printer_get_hard_margins (GtkPrinter *printer,
511 fallback_printer_list_papers (GtkPrinter *printer)
516 static GtkPageSetup *
517 fallback_printer_get_default_page_size (GtkPrinter *printer)
522 static GtkPrintCapabilities
523 fallback_printer_get_capabilities (GtkPrinter *printer)
530 printer_hash_to_sorted_active_list (const gchar *key,
536 printer = GTK_PRINTER (value);
538 if (gtk_printer_get_name (printer) == NULL)
541 if (!gtk_printer_is_active (printer))
544 *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
549 gtk_print_backend_add_printer (GtkPrintBackend *backend,
552 GtkPrintBackendPrivate *priv;
554 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
556 priv = backend->priv;
561 g_hash_table_insert (priv->printers,
562 g_strdup (gtk_printer_get_name (printer)),
563 g_object_ref (printer));
567 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
570 GtkPrintBackendPrivate *priv;
572 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
573 priv = backend->priv;
578 g_hash_table_remove (priv->printers,
579 gtk_printer_get_name (printer));
583 gtk_print_backend_set_list_done (GtkPrintBackend *backend)
585 if (!backend->priv->printer_list_done)
587 backend->priv->printer_list_done = TRUE;
588 g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0);
594 gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
596 GtkPrintBackendPrivate *priv;
599 g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
601 priv = backend->priv;
604 if (priv->printers != NULL)
605 g_hash_table_foreach (priv->printers,
606 (GHFunc) printer_hash_to_sorted_active_list,
609 if (!priv->printer_list_requested && priv->printers != NULL)
611 if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
612 GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
613 priv->printer_list_requested = TRUE;
620 gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
622 g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
624 return print_backend->priv->printer_list_done;
628 gtk_print_backend_find_printer (GtkPrintBackend *backend,
629 const gchar *printer_name)
631 GtkPrintBackendPrivate *priv;
634 g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
636 priv = backend->priv;
639 printer = g_hash_table_lookup (priv->printers, printer_name);
647 gtk_print_backend_print_stream (GtkPrintBackend *backend,
650 GtkPrintJobCompleteFunc callback,
652 GDestroyNotify dnotify)
654 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
656 GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
665 gtk_print_backend_set_password (GtkPrintBackend *backend,
666 const gchar *hostname,
667 const gchar *username,
668 const gchar *password)
670 g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
672 if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
673 GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, hostname, username, password);
677 store_password (GtkEntry *entry,
678 GtkPrintBackend *backend)
680 GtkPrintBackendPrivate *priv = backend->priv;
682 if (priv->password != NULL)
684 memset (priv->password, 0, strlen (priv->password));
685 g_free (priv->password);
688 priv->password = g_strdup (gtk_entry_get_text (entry));
692 store_username (GtkEntry *entry,
693 GtkPrintBackend *backend)
695 GtkPrintBackendPrivate *priv = backend->priv;
697 g_free (priv->username);
698 priv->username = g_strdup (gtk_entry_get_text (entry));
702 password_dialog_response (GtkWidget *dialog,
704 GtkPrintBackend *backend)
706 GtkPrintBackendPrivate *priv = backend->priv;
708 if (response_id == GTK_RESPONSE_OK)
709 gtk_print_backend_set_password (backend, priv->hostname, priv->username, priv->password);
711 gtk_print_backend_set_password (backend, priv->hostname, priv->username, NULL);
713 if (priv->password != NULL)
715 memset (priv->password, 0, strlen (priv->password));
716 g_free (priv->password);
717 priv->password = NULL;
720 g_free (priv->username);
721 priv->username = NULL;
723 gtk_widget_destroy (dialog);
725 g_object_unref (backend);
729 request_password (GtkPrintBackend *backend,
730 const gchar *hostname,
731 const gchar *username,
734 GtkPrintBackendPrivate *priv = backend->priv;
735 GtkWidget *dialog, *username_box, *password_box, *main_box, *label, *icon, *vbox,
736 *password_prompt, *username_prompt,
737 *password_entry, *username_entry;
740 dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL,
741 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
742 GTK_STOCK_OK, GTK_RESPONSE_OK,
745 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
746 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
748 main_box = gtk_hbox_new (FALSE, 0);
751 icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
752 gtk_misc_set_alignment (GTK_MISC (icon), 0.5, 0.0);
753 gtk_misc_set_padding (GTK_MISC (icon), 6, 6);
757 vbox = gtk_vbox_new (FALSE, 0);
758 gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);
761 label = gtk_label_new (NULL);
762 markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", prompt);
763 gtk_label_set_markup (GTK_LABEL (label), markup);
764 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
765 gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
770 username_box = gtk_hbox_new (TRUE, 0);
772 username_prompt = gtk_label_new (_("Username:"));
773 gtk_misc_set_alignment (GTK_MISC (username_prompt), 0.0, 0.5);
775 username_entry = gtk_entry_new ();
776 gtk_entry_set_text (GTK_ENTRY (username_entry), username);
780 password_box = gtk_hbox_new (TRUE, 0);
782 password_prompt = gtk_label_new (_("Password:"));
783 gtk_misc_set_alignment (GTK_MISC (password_prompt), 0.0, 0.5);
785 password_entry = gtk_entry_new ();
786 gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
787 gtk_entry_set_activates_default (GTK_ENTRY (password_entry), TRUE);
791 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_box, TRUE, FALSE, 0);
793 gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
794 gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
796 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
797 gtk_box_pack_start (GTK_BOX (vbox), username_box, FALSE, TRUE, 6);
798 gtk_box_pack_start (GTK_BOX (vbox), password_box, FALSE, TRUE, 6);
800 gtk_box_pack_start (GTK_BOX (username_box), username_prompt, TRUE, TRUE, 0);
801 gtk_box_pack_start (GTK_BOX (username_box), username_entry, TRUE, TRUE, 0);
803 gtk_box_pack_start (GTK_BOX (password_box), password_prompt, TRUE, TRUE, 0);
804 gtk_box_pack_start (GTK_BOX (password_box), password_entry, TRUE, TRUE, 0);
807 gtk_widget_grab_focus (password_entry);
809 priv->hostname = g_strdup (hostname);
810 priv->username = g_strdup (username);
812 g_signal_connect (password_entry, "changed",
813 G_CALLBACK (store_password), backend);
815 g_signal_connect (username_entry, "changed",
816 G_CALLBACK (store_username), backend);
818 g_object_ref (backend);
819 g_signal_connect (G_OBJECT (dialog), "response",
820 G_CALLBACK (password_dialog_response), backend);
822 gtk_widget_show_all (dialog);
826 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
828 /* The lifecycle of print backends and printers are tied, such that
829 * the backend owns the printers, but the printers also ref the backend.
830 * This is so that if the app has a reference to a printer its backend
831 * will be around. However, this results in a cycle, which we break
832 * with this call, which causes the print backend to release its printers.
834 g_object_run_dispose (G_OBJECT (print_backend));
838 #define __GTK_PRINT_BACKEND_C__
839 #include "gtkaliasdef.c"