diff options
-rw-r--r-- | ChangeLog | 55 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 55 | ||||
-rw-r--r-- | gtk/gtk.symbols | 2 | ||||
-rw-r--r-- | gtk/gtkpagesetupunixdialog.c | 30 | ||||
-rw-r--r-- | gtk/gtkprintbackend.c | 307 | ||||
-rw-r--r-- | gtk/gtkprintbackend.h | 88 | ||||
-rw-r--r-- | gtk/gtkprinter.c | 67 | ||||
-rw-r--r-- | gtk/gtkprinter.h | 2 | ||||
-rw-r--r-- | gtk/gtkprintoperation-private.h | 6 | ||||
-rw-r--r-- | gtk/gtkprintoperation-unix.c | 385 | ||||
-rw-r--r-- | gtk/gtkprintoperation.c | 13 | ||||
-rw-r--r-- | gtk/gtkprintunixdialog.c | 27 | ||||
-rw-r--r-- | modules/printbackends/cups/gtkcupsutils.c | 20 | ||||
-rw-r--r-- | modules/printbackends/cups/gtkcupsutils.h | 7 | ||||
-rw-r--r-- | modules/printbackends/cups/gtkprintbackendcups.c | 467 | ||||
-rw-r--r-- | modules/printbackends/cups/gtkprintercups.c | 3 | ||||
-rw-r--r-- | modules/printbackends/lpr/gtkprintbackendlpr.c | 123 | ||||
-rw-r--r-- | modules/printbackends/pdf/gtkprintbackendpdf.c | 123 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rw-r--r-- | tests/testnouiprint.c | 107 |
20 files changed, 1278 insertions, 612 deletions
@@ -1,3 +1,58 @@ +2006-05-04 Alexander Larsson <alexl@redhat.com> + + * gtk/gtk.symbols: + Added new symbols + + * gtk/gtkpagesetupunixdialog.c: + * gtk/gtkprintunixdialog.c: + Destroy backends when finalizing dialogs. + Fix printer leak in selected_printer_changed. + + * gtk/gtkprintbackend.[ch]: + Convert from interface to baseclass. + Move printer hashtable here so that the baseclass can handle + the slightly complicated ownership model. + Add gtk_print_backend_destroy which runs the dispose method, + causing the ref-cycles between the backend and its printers + to be broken. + Add gtk_print_backend_unref_at_idle(). + + * gtk/gtkprinter.[ch]: + GtkPrinter objects now ref their backend so that its always + availible, since its needed for the printer object to work. + This causes a reference-cycle that is broken using + gtk_print_backend_destroy. + Add gtk_printer_compare. + + * gtk/gtkprintoperation-private.h: + * gtk/gtkprintoperation-unix.c: + * gtk/gtkprintoperation.c: + Implement !show_dialog for unix. + Make sure the print data is fully spooled before returning + from a sync run_dialog. + + + * modules/printbackends/cups/gtkcupsutils.[ch]: + Add gtk_cups_request_ipp_add_strings + + * modules/printbackends/cups/gtkprintbackendcups.c: + * modules/printbackends/cups/gtkprintercups.c: + * modules/printbackends/lpr/gtkprintbackendlpr.c: + * modules/printbackends/pdf/gtkprintbackendpdf.c: + Convert backends to derive instead of implementing interface. + Move common code into baseclass. + CUPS: + Remove the printer polling in dispose, not finalize. + In the cups watch, remove the backend at idle instead of + immediately, since the unref can cause the module to be unloaded. + Limit the number of printer attributes requested + Get printer uri in initial printer listing so that we can use + the printer object immediately. + + * tests/Makefile.am: + * tests/testnouiprint.c: + Add testcase for !show_dialog. + 2006-05-04 Matthias Clasen <mclasen@redhat.com> * gtk/gtk.symbols: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index ef7b5f310e..d3df94cc3c 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,58 @@ +2006-05-04 Alexander Larsson <alexl@redhat.com> + + * gtk/gtk.symbols: + Added new symbols + + * gtk/gtkpagesetupunixdialog.c: + * gtk/gtkprintunixdialog.c: + Destroy backends when finalizing dialogs. + Fix printer leak in selected_printer_changed. + + * gtk/gtkprintbackend.[ch]: + Convert from interface to baseclass. + Move printer hashtable here so that the baseclass can handle + the slightly complicated ownership model. + Add gtk_print_backend_destroy which runs the dispose method, + causing the ref-cycles between the backend and its printers + to be broken. + Add gtk_print_backend_unref_at_idle(). + + * gtk/gtkprinter.[ch]: + GtkPrinter objects now ref their backend so that its always + availible, since its needed for the printer object to work. + This causes a reference-cycle that is broken using + gtk_print_backend_destroy. + Add gtk_printer_compare. + + * gtk/gtkprintoperation-private.h: + * gtk/gtkprintoperation-unix.c: + * gtk/gtkprintoperation.c: + Implement !show_dialog for unix. + Make sure the print data is fully spooled before returning + from a sync run_dialog. + + + * modules/printbackends/cups/gtkcupsutils.[ch]: + Add gtk_cups_request_ipp_add_strings + + * modules/printbackends/cups/gtkprintbackendcups.c: + * modules/printbackends/cups/gtkprintercups.c: + * modules/printbackends/lpr/gtkprintbackendlpr.c: + * modules/printbackends/pdf/gtkprintbackendpdf.c: + Convert backends to derive instead of implementing interface. + Move common code into baseclass. + CUPS: + Remove the printer polling in dispose, not finalize. + In the cups watch, remove the backend at idle instead of + immediately, since the unref can cause the module to be unloaded. + Limit the number of printer attributes requested + Get printer uri in initial printer listing so that we can use + the printer object immediately. + + * tests/Makefile.am: + * tests/testnouiprint.c: + Add testcase for !show_dialog. + 2006-05-04 Matthias Clasen <mclasen@redhat.com> * gtk/gtk.symbols: diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index eb09e7da24..afcbe2c123 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -2550,9 +2550,11 @@ gtk_paper_size_get_default gtk_print_backend_error_quark gtk_print_backend_get_type G_GNUC_CONST gtk_print_backend_get_printer_list +gtk_print_backend_printer_list_is_done gtk_print_backend_find_printer gtk_print_backend_print_stream gtk_print_backend_load_modules +gtk_print_backend_unref_at_idle #endif #endif #endif diff --git a/gtk/gtkpagesetupunixdialog.c b/gtk/gtkpagesetupunixdialog.c index 72a5cd074c..5daf854959 100644 --- a/gtk/gtkpagesetupunixdialog.c +++ b/gtk/gtkpagesetupunixdialog.c @@ -110,6 +110,17 @@ static void populate_dialog (GtkPageSetupUnixDialog *dialog static void fill_paper_sizes_from_printer (GtkPageSetupUnixDialog *dialog, GtkPrinter *printer); static void run_custom_paper_dialog (GtkPageSetupUnixDialog *dialog); +static void printer_added_cb (GtkPrintBackend *backend, + GtkPrinter *printer, + GtkPageSetupUnixDialog *dialog); +static void printer_removed_cb (GtkPrintBackend *backend, + GtkPrinter *printer, + GtkPageSetupUnixDialog *dialog); +static void printer_status_cb (GtkPrintBackend *backend, + GtkPrinter *printer, + GtkPageSetupUnixDialog *dialog); + + static const char * const common_paper_sizes[] = { "na_letter", @@ -369,7 +380,9 @@ gtk_page_setup_unix_dialog_finalize (GObject *object) { GtkPageSetupUnixDialog *dialog = GTK_PAGE_SETUP_UNIX_DIALOG (object); GtkPageSetupUnixDialogPrivate *priv = dialog->priv; - + GtkPrintBackend *backend; + GList *node; + if (priv->request_details_tag) { g_source_remove (priv->request_details_tag); @@ -397,6 +410,21 @@ gtk_page_setup_unix_dialog_finalize (GObject *object) g_free (priv->waiting_for_printer); priv->waiting_for_printer = NULL; + for (node = priv->print_backends; node != NULL; node = node->next) + { + backend = GTK_PRINT_BACKEND (node->data); + + g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog); + g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog); + g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog); + + gtk_print_backend_destroy (backend); + g_object_unref (backend); + } + + g_list_free (priv->print_backends); + priv->print_backends = NULL; + G_OBJECT_CLASS (gtk_page_setup_unix_dialog_parent_class)->finalize (object); } diff --git a/gtk/gtkprintbackend.c b/gtk/gtkprintbackend.c index 32e6596d0a..272d2f3957 100644 --- a/gtk/gtkprintbackend.c +++ b/gtk/gtkprintbackend.c @@ -29,7 +29,30 @@ #include "gtkprintbackend.h" #include "gtkalias.h" -static void gtk_print_backend_base_init (gpointer g_class); +#define GTK_PRINT_BACKEND_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendPrivate)) + +static void gtk_print_backend_dispose (GObject *object); + +struct _GtkPrintBackendPrivate +{ + GHashTable *printers; + guint printer_list_requested : 1; + guint printer_list_done : 1; +}; + +enum { + PRINTER_LIST_CHANGED, + PRINTER_LIST_DONE, + PRINTER_ADDED, + PRINTER_REMOVED, + PRINTER_STATUS_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static GObjectClass *backend_parent_class; GQuark gtk_print_backend_error_quark (void) @@ -142,7 +165,7 @@ _gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class) { GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class); GObjectClass *gobject_class = G_OBJECT_CLASS (class); - + module_class->load = gtk_print_backend_module_load; module_class->unload = gtk_print_backend_module_unload; @@ -272,107 +295,255 @@ gtk_print_backend_load_modules () /***************************************** * GtkPrintBackend * *****************************************/ -GType -gtk_print_backend_get_type (void) + +G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT); + +static void +gtk_print_backend_class_init (GtkPrintBackendClass *class) { - static GType print_backend_type = 0; + GObjectClass *object_class; + object_class = (GObjectClass *) class; - if (!print_backend_type) + backend_parent_class = g_type_class_peek_parent (class); + + object_class->dispose = gtk_print_backend_dispose; + + g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate)); + + + signals[PRINTER_LIST_CHANGED] = + g_signal_new ("printer-list-changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[PRINTER_LIST_DONE] = + g_signal_new ("printer-list-done", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintBackendClass, printer_list_done), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[PRINTER_ADDED] = + g_signal_new ("printer-added", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintBackendClass, printer_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_PRINTER); + signals[PRINTER_REMOVED] = + g_signal_new ("printer-removed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintBackendClass, printer_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_PRINTER); + signals[PRINTER_STATUS_CHANGED] = + g_signal_new ("printer-status-changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintBackendClass, printer_status_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_PRINTER); +} + +static void +gtk_print_backend_init (GtkPrintBackend *backend) +{ + GtkPrintBackendPrivate *priv; + + priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); + + priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); +} + +static void +gtk_print_backend_dispose (GObject *object) +{ + GtkPrintBackend *backend; + GtkPrintBackendPrivate *priv; + + backend = GTK_PRINT_BACKEND (object); + priv = backend->priv; + + /* We unref the printers in dispose, not in finalize so that + we can break refcount cycles with gtk_print_backend_destroy */ + if (priv->printers) { - static const GTypeInfo print_backend_info = - { - sizeof (GtkPrintBackendIface), /* class_size */ - gtk_print_backend_base_init, /* base_init */ - NULL, /* base_finalize */ - }; - - print_backend_type = g_type_register_static (G_TYPE_INTERFACE, - "GtkPrintBackend", - &print_backend_info, 0); - - g_type_interface_add_prerequisite (print_backend_type, G_TYPE_OBJECT); + g_hash_table_destroy (priv->printers); + priv->printers = NULL; } - return print_backend_type; + backend_parent_class->dispose (object); } + static void -gtk_print_backend_base_init (gpointer g_class) +printer_hash_to_sorted_active_list (const gchar *key, + gpointer value, + GList **out_list) { - static gboolean initialized = FALSE; + GtkPrinter *printer; + + printer = GTK_PRINTER (value); + + if (gtk_printer_get_name (printer) == NULL) + return; + + if (!gtk_printer_is_active (printer)) + return; + + *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare); +} + + +void +gtk_print_backend_add_printer (GtkPrintBackend *backend, + GtkPrinter *printer) +{ + GtkPrintBackendPrivate *priv; - if (!initialized) - { - GType iface_type = G_TYPE_FROM_INTERFACE (g_class); + g_return_if_fail (GTK_IS_PRINT_BACKEND (backend)); - g_signal_new ("printer-list-changed", - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkPrintBackendIface, printer_list_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - g_signal_new ("printer-added", - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkPrintBackendIface, printer_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - g_signal_new ("printer-removed", - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkPrintBackendIface, printer_removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - g_signal_new ("printer-status-changed", - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkPrintBackendIface, printer_status_changed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + priv = backend->priv; - initialized = TRUE; + if (!priv->printers) + return; + + g_hash_table_insert (priv->printers, + g_strdup (gtk_printer_get_name (printer)), + g_object_ref (printer)); +} + +void +gtk_print_backend_remove_printer (GtkPrintBackend *backend, + GtkPrinter *printer) +{ + GtkPrintBackendPrivate *priv; + + g_return_if_fail (GTK_IS_PRINT_BACKEND (backend)); + priv = backend->priv; + + if (!priv->printers) + return; + + g_hash_table_remove (priv->printers, + gtk_printer_get_name (printer)); +} + +void +gtk_print_backend_set_list_done (GtkPrintBackend *backend) +{ + if (!backend->priv->printer_list_done) + { + backend->priv->printer_list_done = TRUE; + g_signal_emit (backend, signals[PRINTER_LIST_DONE], 0); } } + GList * -gtk_print_backend_get_printer_list (GtkPrintBackend *print_backend) +gtk_print_backend_get_printer_list (GtkPrintBackend *backend) { - g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), NULL); + GtkPrintBackendPrivate *priv; + GList *result; + + g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL); + + priv = backend->priv; + + result = NULL; + if (priv->printers != NULL) + g_hash_table_foreach (priv->printers, + (GHFunc) printer_hash_to_sorted_active_list, + &result); + + if (!priv->printer_list_requested && priv->printers != NULL) + { + if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list) + GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend); + priv->printer_list_requested = TRUE; + } + + return result;; +} - return GTK_PRINT_BACKEND_GET_IFACE (print_backend)->get_printer_list (print_backend); +gboolean +gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend) +{ + g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE); + return print_backend->priv->printer_list_done; } GtkPrinter * -gtk_print_backend_find_printer (GtkPrintBackend *print_backend, +gtk_print_backend_find_printer (GtkPrintBackend *backend, const gchar *printer_name) { - g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), NULL); + GtkPrintBackendPrivate *priv; + GtkPrinter *printer; + + g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL); + + priv = backend->priv; - return GTK_PRINT_BACKEND_GET_IFACE (print_backend)->find_printer (print_backend, printer_name); + if (priv->printers) + printer = g_hash_table_lookup (priv->printers, printer_name); + else + printer = NULL; + return printer; } void -gtk_print_backend_print_stream (GtkPrintBackend *print_backend, +gtk_print_backend_print_stream (GtkPrintBackend *backend, GtkPrintJob *job, gint data_fd, GtkPrintJobCompleteFunc callback, gpointer user_data, GDestroyNotify dnotify) { - g_return_if_fail (GTK_IS_PRINT_BACKEND (print_backend)); - - GTK_PRINT_BACKEND_GET_IFACE (print_backend)->print_stream (print_backend, - job, - data_fd, - callback, - user_data, - dnotify); + g_return_if_fail (GTK_IS_PRINT_BACKEND (backend)); + + GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend, + job, + data_fd, + callback, + user_data, + dnotify); +} + +static gboolean +unref_at_idle_cb (gpointer data) +{ + g_object_unref (data); + return FALSE; +} + +void +gtk_print_backend_unref_at_idle (GtkPrintBackend *print_backend) +{ + g_idle_add (unref_at_idle_cb, print_backend); +} + +void +gtk_print_backend_destroy (GtkPrintBackend *print_backend) +{ + /* The lifecycle of print backends and printers are tied, such that + the backend owns the printers, but the printers also ref the backend. + This is so that if the app has a reference to a printer its backend + will be around. However, this results in a cycle, which we break + with this call, which causes the print backend to release its printers. + */ + g_object_run_dispose (G_OBJECT (print_backend)); } #define __GTK_PRINT_BACKEND_C__ diff --git a/gtk/gtkprintbackend.h b/gtk/gtkprintbackend.h index 4e2a05c4b3..fc48690ba3 100644 --- a/gtk/gtkprintbackend.h +++ b/gtk/gtkprintbackend.h @@ -39,7 +39,8 @@ G_BEGIN_DECLS -typedef struct _GtkPrintBackendIface GtkPrintBackendIface; +typedef struct _GtkPrintBackendClass GtkPrintBackendClass; +typedef struct _GtkPrintBackendPrivate GtkPrintBackendPrivate; #define GTK_PRINT_BACKEND_ERROR (gtk_print_backend_error_quark ()) @@ -51,22 +52,28 @@ typedef enum GQuark gtk_print_backend_error_quark (void); -#define GTK_TYPE_PRINT_BACKEND (gtk_print_backend_get_type ()) -#define GTK_PRINT_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND, GtkPrintBackend)) -#define GTK_IS_PRINT_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND)) -#define GTK_PRINT_BACKEND_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendIface)) +#define GTK_TYPE_PRINT_BACKEND (gtk_print_backend_get_type ()) +#define GTK_PRINT_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND, GtkPrintBackend)) +#define GTK_PRINT_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendClass)) +#define GTK_IS_PRINT_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND)) +#define GTK_IS_PRINT_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND)) +#define GTK_PRINT_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendClass)) -struct _GtkPrintBackendIface +struct _GtkPrintBackend { - GTypeInterface base_iface; + GObject parent_instance; - /* Global backend methods: */ - GList * (*get_printer_list) (GtkPrintBackend *printer_backend); + GtkPrintBackendPrivate *priv; +}; - GtkPrinter * (*find_printer) (GtkPrintBackend *print_backend, - const gchar *printer_name); - void (*print_stream) (GtkPrintBackend *print_backend, - GtkPrintJob *job, +struct _GtkPrintBackendClass +{ + GObjectClass parent_class; + + /* Global backend methods: */ + void (*request_printer_list) (GtkPrintBackend *backend); + void (*print_stream) (GtkPrintBackend *backend, + GtkPrintJob *job, gint data_fd, GtkPrintJobCompleteFunc callback, gpointer user_data, @@ -97,26 +104,49 @@ struct _GtkPrintBackendIface double *left, double *right); - /* Signals - */ - void (*printer_list_changed) (void); - void (*printer_added) (GtkPrinter *printer); - void (*printer_removed) (GtkPrinter *printer); - void (*printer_status_changed) (GtkPrinter *printer); + /* Signals */ + void (*printer_list_changed) (GtkPrintBackend *backend); + void (*printer_list_done) (GtkPrintBackend *backend); + void (*printer_added) (GtkPrintBackend *backend, + GtkPrinter *printer); + void (*printer_removed) (GtkPrintBackend *backend, + GtkPrinter *printer); + void (*printer_status_changed) (GtkPrintBackend *backend, + GtkPrinter *printer); + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); + void (*_gtk_reserved5) (void); + void (*_gtk_reserved6) (void); + void (*_gtk_reserved7) (void); }; GType gtk_print_backend_get_type (void) G_GNUC_CONST; -GList *gtk_print_backend_get_printer_list (GtkPrintBackend *print_backend); -GtkPrinter *gtk_print_backend_find_printer (GtkPrintBackend *print_backend, - const gchar *printer_name); -void gtk_print_backend_print_stream (GtkPrintBackend *print_backend, - GtkPrintJob *job, - gint data_fd, - GtkPrintJobCompleteFunc callback, - gpointer user_data, - GDestroyNotify dnotify); -GList * gtk_print_backend_load_modules (void); +GList *gtk_print_backend_get_printer_list (GtkPrintBackend *print_backend); +gboolean gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend); +GtkPrinter *gtk_print_backend_find_printer (GtkPrintBackend *print_backend, + const gchar *printer_name); +void gtk_print_backend_print_stream (GtkPrintBackend *print_backend, + GtkPrintJob *job, + gint data_fd, + GtkPrintJobCompleteFunc callback, + gpointer user_data, + GDestroyNotify dnotify); +GList * gtk_print_backend_load_modules (void); +void gtk_print_backend_unref_at_idle (GtkPrintBackend *print_backend); +void gtk_print_backend_destroy (GtkPrintBackend *print_backend); + +/* Backend-only functions for GtkPrintBackend */ + +void gtk_print_backend_add_printer (GtkPrintBackend *print_backend, + GtkPrinter *printer); +void gtk_print_backend_remove_printer (GtkPrintBackend *print_backend, + GtkPrinter *printer); +void gtk_print_backend_set_list_done (GtkPrintBackend *backend); /* Backend-only functions for GtkPrinter */ diff --git a/gtk/gtkprinter.c b/gtk/gtkprinter.c index 4ae748cec0..e9a197cb9c 100644 --- a/gtk/gtkprinter.c +++ b/gtk/gtkprinter.c @@ -52,7 +52,6 @@ struct _GtkPrinterPrivate gchar *state_message; gint job_count; - /* Not ref:ed, backend owns printer. */ GtkPrintBackend *backend; }; @@ -215,6 +214,9 @@ gtk_printer_finalize (GObject *object) g_free (priv->state_message); g_free (priv->icon_name); + if (priv->backend) + g_object_unref (priv->backend); + G_OBJECT_CLASS (gtk_printer_parent_class)->finalize (object); } @@ -234,7 +236,7 @@ gtk_printer_set_property (GObject *object, break; case PROP_BACKEND: - priv->backend = GTK_PRINT_BACKEND (g_value_get_object (value)); + priv->backend = GTK_PRINT_BACKEND (g_value_dup_object (value)); break; case PROP_IS_VIRTUAL: @@ -340,16 +342,6 @@ gtk_printer_get_backend (GtkPrinter *printer) return printer->priv->backend; } -void -gtk_printer_set_backend (GtkPrinter *printer, - GtkPrintBackend *backend) -{ - g_return_if_fail (GTK_IS_PRINTER (printer)); - g_return_if_fail (GTK_IS_PRINT_BACKEND (backend)); - - printer->priv->backend = backend; -} - /** * gtk_printer_get_name: * @printer: a #GtkPrinter @@ -663,8 +655,8 @@ gtk_printer_set_is_default (GtkPrinter *printer, void _gtk_printer_request_details (GtkPrinter *printer) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); - return backend_iface->printer_request_details (printer); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); + return backend_class->printer_request_details (printer); } GtkPrinterOptionSet * @@ -672,16 +664,16 @@ _gtk_printer_get_options (GtkPrinter *printer, GtkPrintSettings *settings, GtkPageSetup *page_setup) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); - return backend_iface->printer_get_options (printer, settings, page_setup); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); + return backend_class->printer_get_options (printer, settings, page_setup); } gboolean _gtk_printer_mark_conflicts (GtkPrinter *printer, GtkPrinterOptionSet *options) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); - return backend_iface->printer_mark_conflicts (printer, options); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); + return backend_class->printer_mark_conflicts (printer, options); } void @@ -689,8 +681,8 @@ _gtk_printer_get_settings_from_options (GtkPrinter *printer, GtkPrinterOptionSet *options, GtkPrintSettings *settings) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); - return backend_iface->printer_get_settings_from_options (printer, options, settings); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); + return backend_class->printer_get_settings_from_options (printer, options, settings); } void @@ -699,8 +691,8 @@ _gtk_printer_prepare_for_print (GtkPrinter *printer, GtkPrintSettings *settings, GtkPageSetup *page_setup) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); - return backend_iface->printer_prepare_for_print (printer, print_job, settings, page_setup); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); + return backend_class->printer_prepare_for_print (printer, print_job, settings, page_setup); } cairo_surface_t * @@ -709,17 +701,17 @@ _gtk_printer_create_cairo_surface (GtkPrinter *printer, gdouble height, gint cache_fd) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); - return backend_iface->printer_create_cairo_surface (printer, width, height, cache_fd); + return backend_class->printer_create_cairo_surface (printer, width, height, cache_fd); } GList * _gtk_printer_list_papers (GtkPrinter *printer) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); - return backend_iface->printer_list_papers (printer); + return backend_class->printer_list_papers (printer); } void @@ -729,9 +721,28 @@ _gtk_printer_get_hard_margins (GtkPrinter *printer, gdouble *left, gdouble *right) { - GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_GET_CLASS (printer->priv->backend); - backend_iface->printer_get_hard_margins (printer, top, bottom, left, right); + backend_class->printer_get_hard_margins (printer, top, bottom, left, right); +} + +gint +gtk_printer_compare (GtkPrinter *a, GtkPrinter *b) +{ + const char *name_a, *name_b; + + g_assert (GTK_IS_PRINTER (a) && GTK_IS_PRINTER (b)); + + name_a = gtk_printer_get_name (a); + name_b = gtk_printer_get_name (b); + if (name_a == NULL && name_b == NULL) + return 0; + else if (name_a == NULL) + return G_MAXINT; + else if (name_b == NULL) + return G_MININT; + else + return g_ascii_strcasecmp (name_a, name_b); } #define __GTK_PRINTER_C__ diff --git a/gtk/gtkprinter.h b/gtk/gtkprinter.h index 90a0e6b0ae..6c9e056e15 100644 --- a/gtk/gtkprinter.h +++ b/gtk/gtkprinter.h @@ -78,6 +78,8 @@ gboolean gtk_printer_is_active (GtkPrinter *printer gboolean gtk_printer_is_virtual (GtkPrinter *printer); gboolean gtk_printer_is_default (GtkPrinter *printer); +gint gtk_printer_compare (GtkPrinter *a, + GtkPrinter *b); G_END_DECLS diff --git a/gtk/gtkprintoperation-private.h b/gtk/gtkprintoperation-private.h index cf38582dcc..2213967162 100644 --- a/gtk/gtkprintoperation-private.h +++ b/gtk/gtkprintoperation-private.h @@ -61,7 +61,8 @@ struct _GtkPrintOperationPrivate GtkPageSetup *page_setup); void (*end_page) (GtkPrintOperation *operation, GtkPrintContext *print_context); - void (*end_run) (GtkPrintOperation *operation); + void (*end_run) (GtkPrintOperation *operation, + gboolean wait); GDestroyNotify free_platform_data; }; @@ -70,7 +71,8 @@ GtkPrintOperationResult _gtk_print_operation_platform_backend_run_dialog (GtkPri gboolean *do_print, GError **error); -typedef void (* GtkPrintOperationPrintFunc) (GtkPrintOperation *op); +typedef void (* GtkPrintOperationPrintFunc) (GtkPrintOperation *op, + gboolean wait); void _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation *op, GtkWindow *parent, diff --git a/gtk/gtkprintoperation-unix.c b/gtk/gtkprintoperation-unix.c index 4f74bf52ac..3b6f5561f5 100644 --- a/gtk/gtkprintoperation-unix.c +++ b/gtk/gtkprintoperation-unix.c @@ -42,8 +42,17 @@ typedef struct { GtkPrintJob *job; /* the job we are sending to the printer */ gulong job_status_changed_tag; GtkWindow *parent; /* just in case we need to throw error dialogs */ + GMainLoop *loop; + gboolean data_sent; } GtkPrintOperationUnix; +typedef struct _PrinterFinder PrinterFinder; + +static void printer_finder_free (PrinterFinder *finder); +static void find_printer (const char *printer, + GFunc func, + gpointer data); + static void unix_start_page (GtkPrintOperation *op, GtkPrintContext *print_context, @@ -100,18 +109,37 @@ unix_finish_send (GtkPrintJob *job, gtk_window_present (GTK_WINDOW (edialog)); } + + op_unix->data_sent = TRUE; + if (op_unix->loop) + g_main_loop_quit (op_unix->loop); } static void -unix_end_run (GtkPrintOperation *op) +unix_end_run (GtkPrintOperation *op, + gboolean wait) { GtkPrintOperationUnix *op_unix = op->priv->platform_data; - + + if (wait) + op_unix->loop = g_main_loop_new (NULL, FALSE); + /* TODO: Check for error */ gtk_print_job_send (op_unix->job, unix_finish_send, op_unix, NULL, NULL); + + if (wait) + { + if (!op_unix->data_sent) + { + GDK_THREADS_LEAVE (); + g_main_loop_run (op_unix->loop); + GDK_THREADS_ENTER (); + } + g_main_loop_unref (op_unix->loop); + } } static void @@ -154,6 +182,8 @@ typedef struct { GtkPrintOperationResult result; GtkPrintOperationPrintFunc print_cb; GDestroyNotify destroy; + GtkWindow *parent; + GMainLoop *loop; } PrintResponseData; static void @@ -166,41 +196,29 @@ print_response_data_free (gpointer data) } static void -handle_print_response (GtkWidget *dialog, - gint response, - gpointer data) +finish_print (PrintResponseData *rdata, + GtkPrinter *printer, + GtkPageSetup *page_setup, + GtkPrintSettings *settings) { - GtkPrintUnixDialog *pd = GTK_PRINT_UNIX_DIALOG (dialog); - PrintResponseData *rdata = data; GtkPrintOperation *op = rdata->op; GtkPrintOperationPrivate *priv = op->priv; - if (response == GTK_RESPONSE_OK) + priv->start_page = unix_start_page; + priv->end_page = unix_end_page; + priv->end_run = unix_end_run; + + if (rdata->do_print) { GtkPrintOperationUnix *op_unix; - GtkPrinter *printer; - GtkPrintSettings *settings; - GtkPageSetup *page_setup; - - rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY; - - printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd)); - if (printer == NULL) - goto out; - - rdata->do_print = TRUE; - - settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd)); - page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd)); gtk_print_operation_set_print_settings (op, settings); - + op_unix = g_new0 (GtkPrintOperationUnix, 1); op_unix->job = gtk_print_job_new (priv->job_name, printer, settings, page_setup); - g_object_unref (settings); rdata->op->priv->surface = gtk_print_job_get_surface (op_unix->job, rdata->error); if (op->priv->surface == NULL) @@ -216,7 +234,7 @@ handle_print_response (GtkWidget *dialog, g_signal_connect (op_unix->job, "status_changed", G_CALLBACK (job_status_changed_cb), op); - op_unix->parent = gtk_window_get_transient_for (GTK_WINDOW (pd)); + op_unix->parent = rdata->parent; priv->dpi_x = 72; priv->dpi_y = 72; @@ -236,17 +254,11 @@ handle_print_response (GtkWidget *dialog, priv->manual_orientation = op_unix->job->rotate_to_orientation; } - priv->start_page = unix_start_page; - priv->end_page = unix_end_page; - priv->end_run = unix_end_run; - out: - gtk_widget_destroy (GTK_WIDGET (pd)); - if (rdata->print_cb) { if (rdata->do_print) - rdata->print_cb (op); + rdata->print_cb (op, FALSE); else _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); } @@ -255,6 +267,81 @@ handle_print_response (GtkWidget *dialog, rdata->destroy (rdata); } +static void +handle_print_response (GtkWidget *dialog, + gint response, + gpointer data) +{ + GtkPrintUnixDialog *pd = GTK_PRINT_UNIX_DIALOG (dialog); + PrintResponseData *rdata = data; + GtkPrintSettings *settings = NULL; + GtkPageSetup *page_setup = NULL; + GtkPrinter *printer = NULL; + + if (response == GTK_RESPONSE_OK) + { + rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY; + + printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd)); + if (printer == NULL) + goto out; + + rdata->do_print = TRUE; + + settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd)); + page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd)); + } + + out: + finish_print (rdata, printer, page_setup, settings); + + if (settings) + g_object_unref (settings); + + gtk_widget_destroy (GTK_WIDGET (pd)); +} + + +static void +found_printer (GtkPrinter *printer, + PrintResponseData *rdata) +{ + GtkPrintOperation *op = rdata->op; + GtkPrintOperationPrivate *priv = op->priv; + GtkPrintSettings *settings = NULL; + GtkPageSetup *page_setup = NULL; + + if (rdata->loop) + g_main_loop_quit (rdata->loop); + + if (printer != NULL) { + rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY; + + rdata->do_print = TRUE; + + if (priv->print_settings) + settings = gtk_print_settings_copy (priv->print_settings); + else + settings = gtk_print_settings_new (); + + gtk_print_settings_set_printer (settings, + gtk_printer_get_name (printer)); + + if (priv->default_page_setup) + page_setup = gtk_page_setup_copy (priv->default_page_setup); + else + page_setup = gtk_page_setup_new (); + } + + finish_print (rdata, printer, page_setup, settings); + + if (settings) + g_object_unref (settings); + + if (page_setup) + g_object_unref (page_setup); +} + void _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation *op, GtkWindow *parent, @@ -262,6 +349,7 @@ _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation { GtkWidget *pd; PrintResponseData *rdata; + const char *printer_name; rdata = g_new (PrintResponseData, 1); rdata->op = g_object_ref (op); @@ -269,15 +357,29 @@ _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL; rdata->error = NULL; rdata->print_cb = print_cb; + rdata->parent = parent; + rdata->loop = NULL; rdata->destroy = print_response_data_free; - pd = get_print_dialog (op, parent); - gtk_window_set_modal (GTK_WINDOW (pd), TRUE); - - g_signal_connect (pd, "response", - G_CALLBACK (handle_print_response), rdata); + if (op->priv->show_dialog) + { + pd = get_print_dialog (op, parent); + gtk_window_set_modal (GTK_WINDOW (pd), TRUE); - gtk_window_present (GTK_WINDOW (pd)); + g_signal_connect (pd, "response", + G_CALLBACK (handle_print_response), rdata); + + gtk_window_present (GTK_WINDOW (pd)); + } + else + { + printer_name = NULL; + if (op->priv->print_settings) + printer_name = gtk_print_settings_get_printer (op->priv->print_settings); + + find_printer (printer_name, + (GFunc) found_printer, rdata); + } } GtkPrintOperationResult @@ -289,6 +391,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, GtkWidget *pd; PrintResponseData rdata; gint response; + const char *printer_name; rdata.op = op; rdata.do_print = FALSE; @@ -296,14 +399,34 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, rdata.error = error; rdata.print_cb = NULL; rdata.destroy = NULL; + rdata.parent = parent; + rdata.loop = NULL; - pd = get_print_dialog (op, parent); + if (op->priv->show_dialog) + { + pd = get_print_dialog (op, parent); + response = gtk_dialog_run (GTK_DIALOG (pd)); + handle_print_response (pd, response, &rdata); + } + else + { + printer_name = NULL; + if (op->priv->print_settings) + printer_name = gtk_print_settings_get_printer (op->priv->print_settings); + + rdata.loop = g_main_loop_new (NULL, FALSE); + find_printer (printer_name, + (GFunc) found_printer, &rdata); - response = gtk_dialog_run (GTK_DIALOG (pd)); - handle_print_response (pd, response, &rdata); + GDK_THREADS_LEAVE (); + g_main_loop_run (rdata.loop); + GDK_THREADS_ENTER (); - *do_print = rdata.do_print; + g_main_loop_unref (rdata.loop); + } + *do_print = rdata.do_print; + return rdata.result; } @@ -448,6 +571,184 @@ gtk_print_run_page_setup_dialog_async (GtkWindow *parent, gtk_window_present (GTK_WINDOW (dialog)); } +struct _PrinterFinder { + gboolean found_printer; + GFunc func; + gpointer data; + char *printer_name; + GList *backends; + guint timeout_tag; + GtkPrinter *printer; + GtkPrinter *default_printer; + GtkPrinter *first_printer; +}; + +static gboolean +find_printer_idle (gpointer data) +{ + PrinterFinder *finder = data; + GtkPrinter *printer; + + if (finder->printer != NULL) + printer = finder->printer; + else if (finder->default_printer != NULL) + printer = finder->default_printer; + else if (finder->first_printer != NULL) + printer = finder->first_printer; + else + printer = NULL; + + finder->func (printer, finder->data); + + printer_finder_free (finder); + + return FALSE; +} + +static void +printer_added_cb (GtkPrintBackend *backend, + GtkPrinter *printer, + PrinterFinder *finder) +{ + if (gtk_printer_is_virtual (printer) || + finder->found_printer) + return; + + if (finder->printer_name != NULL && + strcmp (gtk_printer_get_name (printer), finder->printer_name) == 0) + { + finder->printer = g_object_ref (printer); + finder->found_printer = TRUE; + } + else if (finder->default_printer == NULL && + gtk_printer_is_default (printer)) + { + finder->default_printer = g_object_ref (printer); + if (finder->printer_name == NULL) + finder->found_printer = TRUE; + } + else + if (finder->first_printer == NULL) + finder->first_printer = g_object_ref (printer); + + if (finder->found_printer) + g_idle_add (find_printer_idle, finder); +} + +static void +printer_list_done_cb (GtkPrintBackend *backend, + PrinterFinder *finder) +{ + finder->backends = g_list_remove (finder->backends, backend); + + g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder); + g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder); + + gtk_print_backend_destroy (backend); + g_object_unref (backend); + + if (finder->backends == NULL && !finder->found_printer) + g_idle_add (find_printer_idle, finder); +} + +static void +find_printer_init (PrinterFinder *finder, + GtkPrintBackend *backend) +{ + GList *list; + GList *node; + + list = gtk_print_backend_get_printer_list (backend); + + node = list; + while (node != NULL) + { + printer_added_cb (backend, node->data, finder); + node = node->next; + + if (finder->found_printer) + break; + } + + g_list_free (list); + + if (gtk_print_backend_printer_list_is_done (backend)) + { + finder->backends = g_list_remove (finder->backends, backend); + gtk_print_backend_destroy (backend); + g_object_unref (backend); + } + else + { + g_signal_connect (backend, + "printer-added", + (GCallback) printer_added_cb, + finder); + g_signal_connect (backend, + "printer-list-done", + (GCallback) printer_list_done_cb, + finder); + } + +} + +static void +printer_finder_free (PrinterFinder *finder) +{ + GList *l; + + g_free (finder->printer_name); + + if (finder->printer) + g_object_unref (finder->printer); + + if (finder->default_printer) + g_object_unref (finder->default_printer); + + if (finder->first_printer) + g_object_unref (finder->first_printer); + + for (l = finder->backends; l != NULL; l = l->next) + { + GtkPrintBackend *backend = l->data; + g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder); + g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder); + gtk_print_backend_destroy (backend); + g_object_unref (backend); + } + + g_list_free (finder->backends); + + g_free (finder); +} + +static void +find_printer (const char *printer, + GFunc func, + gpointer data) +{ + GList *node, *next; + PrinterFinder *finder; + + finder = g_new0 (PrinterFinder, 1); + + finder->printer_name = g_strdup (printer); + finder->func = func; + finder->data = data; + + finder->backends = NULL; + if (g_module_supported ()) + finder->backends = gtk_print_backend_load_modules (); + + for (node = finder->backends; !finder->found_printer && node != NULL; node = next) + { + next = node->next; + find_printer_init (finder, GTK_PRINT_BACKEND (node->data)); + } + + if (finder->backends == NULL && !finder->found_printer) + g_idle_add (find_printer_idle, finder); +} #define __GTK_PRINT_OPERATION_UNIX_C__ #include "gtkaliasdef.c" diff --git a/gtk/gtkprintoperation.c b/gtk/gtkprintoperation.c index cd52b8eb1f..998717d753 100644 --- a/gtk/gtkprintoperation.c +++ b/gtk/gtkprintoperation.c @@ -1115,7 +1115,8 @@ pdf_end_page (GtkPrintOperation *op, } static void -pdf_end_run (GtkPrintOperation *op) +pdf_end_run (GtkPrintOperation *op, + gboolean wait) { GtkPrintOperationPrivate *priv = op->priv; @@ -1161,7 +1162,8 @@ run_pdf (GtkPrintOperation *op, } static void -print_pages (GtkPrintOperation *op) +print_pages (GtkPrintOperation *op, + gboolean wait) { GtkPrintOperationPrivate *priv = op->priv; int page, range; @@ -1289,8 +1291,7 @@ print_pages (GtkPrintOperation *op) g_object_unref (initial_page_setup); cairo_surface_finish (priv->surface); - priv->end_run (op); - + priv->end_run (op, wait); } /** @@ -1343,7 +1344,7 @@ gtk_print_operation_run (GtkPrintOperation *op, &do_print, error); if (do_print) - print_pages (op); + print_pages (op, TRUE); else _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); @@ -1384,7 +1385,7 @@ gtk_print_operation_run_async (GtkPrintOperation *op, { run_pdf (op, parent, &do_print, NULL); if (do_print) - print_pages (op); + print_pages (op, FALSE); else _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); } diff --git a/gtk/gtkprintunixdialog.c b/gtk/gtkprintunixdialog.c index f2cdd8040a..59cf75321b 100644 --- a/gtk/gtkprintunixdialog.c +++ b/gtk/gtkprintunixdialog.c @@ -73,6 +73,15 @@ static void unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog); static void selected_printer_changed (GtkTreeSelection *selection, GtkPrintUnixDialog *dialog); static void clear_per_printer_ui (GtkPrintUnixDialog *dialog); +static void printer_added_cb (GtkPrintBackend *backend, + GtkPrinter *printer, + GtkPrintUnixDialog *dialog); +static void printer_removed_cb (GtkPrintBackend *backend, + GtkPrinter *printer, + GtkPrintUnixDialog *dialog); +static void printer_status_cb (GtkPrintBackend *backend, + GtkPrinter *printer, + GtkPrintUnixDialog *dialog); enum { PROP_0, @@ -281,6 +290,8 @@ gtk_print_unix_dialog_finalize (GObject *object) { GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object); GtkPrintUnixDialogPrivate *priv = dialog->priv; + GtkPrintBackend *backend; + GList *node; unschedule_idle_mark_conflicts (dialog); @@ -339,6 +350,21 @@ gtk_print_unix_dialog_finalize (GObject *object) g_free (priv->format_for_printer); priv->format_for_printer = NULL; + for (node = priv->print_backends; node != NULL; node = node->next) + { + backend = GTK_PRINT_BACKEND (node->data); + + g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog); + g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog); + g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog); + + gtk_print_backend_destroy (backend); + g_object_unref (backend); + } + + g_list_free (priv->print_backends); + priv->print_backends = NULL; + G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object); } @@ -1164,6 +1190,7 @@ selected_printer_changed (GtkTreeSelection *selection, g_signal_connect (printer, "details-acquired", G_CALLBACK (printer_details_acquired), dialog); _gtk_printer_request_details (printer); + g_object_unref (printer); return; } diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c index 458e1c4219..2ebf4a785f 100644 --- a/modules/printbackends/cups/gtkcupsutils.c +++ b/modules/printbackends/cups/gtkcupsutils.c @@ -242,6 +242,26 @@ gtk_cups_request_ipp_add_string (GtkCupsRequest *request, value); } +void +gtk_cups_request_ipp_add_strings (GtkCupsRequest *request, + ipp_tag_t group, + ipp_tag_t tag, + const char *name, + int num_values, + const char *charset, + const char * const *values) +{ + ippAddStrings (request->ipp_request, + group, + tag, + name, + num_values, + charset, + values); +} + + + typedef struct { const char *name; diff --git a/modules/printbackends/cups/gtkcupsutils.h b/modules/printbackends/cups/gtkcupsutils.h index f49cd2e9bc..88fb8810f2 100644 --- a/modules/printbackends/cups/gtkcupsutils.h +++ b/modules/printbackends/cups/gtkcupsutils.h @@ -109,6 +109,13 @@ void gtk_cups_request_ipp_add_string (GtkCupsRequest *request, const char *name, const char *charset, const char *value); +void gtk_cups_request_ipp_add_strings (GtkCupsRequest *request, + ipp_tag_t group, + ipp_tag_t tag, + const char *name, + int num_values, + const char *charset, + const char * const *values); gboolean gtk_cups_request_read_write (GtkCupsRequest *request); GtkCupsPollState gtk_cups_request_get_poll_state (GtkCupsRequest *request); void gtk_cups_request_free (GtkCupsRequest *request); diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index 0e10c275b0..13bdfdb0d4 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -89,14 +89,12 @@ typedef struct struct _GtkPrintBackendCupsClass { - GObjectClass parent_class; + GtkPrintBackendClass parent_class; }; struct _GtkPrintBackendCups { - GObject parent_instance; - - GHashTable *printers; + GtkPrintBackend parent_instance; char *default_printer; @@ -108,10 +106,10 @@ struct _GtkPrintBackendCups static GObjectClass *backend_parent_class; static void gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class); -static void gtk_print_backend_cups_iface_init (GtkPrintBackendIface *iface); static void gtk_print_backend_cups_init (GtkPrintBackendCups *impl); static void gtk_print_backend_cups_finalize (GObject *object); -static GList * cups_get_printer_list (GtkPrintBackend *print_backend); +static void gtk_print_backend_cups_dispose (GObject *object); +static void cups_get_printer_list (GtkPrintBackend *print_backend); static void cups_request_execute (GtkPrintBackendCups *print_backend, GtkCupsRequest *request, GtkPrintCupsResponseCallbackFunc callback, @@ -145,6 +143,17 @@ static void cups_begin_polling_info (GtkPrintBack GtkPrintJob *job, int job_id); static gboolean cups_job_info_poll_timeout (gpointer user_data); +static void gtk_print_backend_cups_print_stream (GtkPrintBackend *backend, + GtkPrintJob *job, + gint data_fd, + GtkPrintJobCompleteFunc callback, + gpointer user_data, + GDestroyNotify dnotify); +static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter *printer, + gdouble width, + gdouble height, + gint cache_fd); + static void gtk_print_backend_cups_register_type (GTypeModule *module) @@ -164,21 +173,10 @@ gtk_print_backend_cups_register_type (GTypeModule *module) (GInstanceInitFunc) gtk_print_backend_cups_init }; - static const GInterfaceInfo print_backend_info = - { - (GInterfaceInitFunc) gtk_print_backend_cups_iface_init, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - print_backend_cups_type = g_type_module_register_type (module, - G_TYPE_OBJECT, + GTK_TYPE_PRINT_BACKEND, "GtkPrintBackendCups", &print_backend_cups_info, 0); - g_type_module_add_interface (module, - print_backend_cups_type, - GTK_TYPE_PRINT_BACKEND, - &print_backend_info); } } @@ -229,10 +227,23 @@ static void gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class); backend_parent_class = g_type_class_peek_parent (class); gobject_class->finalize = gtk_print_backend_cups_finalize; + gobject_class->dispose = gtk_print_backend_cups_dispose; + + backend_class->request_printer_list = cups_get_printer_list; + backend_class->print_stream = gtk_print_backend_cups_print_stream; + backend_class->printer_request_details = cups_printer_request_details; + backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface; + backend_class->printer_get_options = cups_printer_get_options; + backend_class->printer_mark_conflicts = cups_printer_mark_conflicts; + backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options; + backend_class->printer_prepare_for_print = cups_printer_prepare_for_print; + backend_class->printer_list_papers = cups_printer_list_papers; + backend_class->printer_get_hard_margins = cups_printer_get_hard_margins; } static cairo_status_t @@ -272,18 +283,6 @@ cups_printer_create_cairo_surface (GtkPrinter *printer, return surface; } -static GtkPrinter * -gtk_print_backend_cups_find_printer (GtkPrintBackend *print_backend, - const gchar *printer_name) -{ - GtkPrintBackendCups *cups_print_backend; - - cups_print_backend = GTK_PRINT_BACKEND_CUPS (print_backend); - - return (GtkPrinter *) g_hash_table_lookup (cups_print_backend->printers, - printer_name); -} - typedef struct { GtkPrintJobCompleteFunc callback; GtkPrintJob *job; @@ -417,30 +416,10 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend, static void -gtk_print_backend_cups_iface_init (GtkPrintBackendIface *iface) -{ - iface->get_printer_list = cups_get_printer_list; - iface->find_printer = gtk_print_backend_cups_find_printer; - iface->print_stream = gtk_print_backend_cups_print_stream; - iface->printer_request_details = cups_printer_request_details; - iface->printer_create_cairo_surface = cups_printer_create_cairo_surface; - iface->printer_get_options = cups_printer_get_options; - iface->printer_mark_conflicts = cups_printer_mark_conflicts; - iface->printer_get_settings_from_options = cups_printer_get_settings_from_options; - iface->printer_prepare_for_print = cups_printer_prepare_for_print; - iface->printer_list_papers = cups_printer_list_papers; - iface->printer_get_hard_margins = cups_printer_get_hard_margins; -} - -static void gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups) { backend_cups->list_printers_poll = 0; backend_cups->list_printers_pending = FALSE; - backend_cups->printers = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); cups_request_default_printer (backend_cups); } @@ -452,18 +431,27 @@ gtk_print_backend_cups_finalize (GObject *object) backend_cups = GTK_PRINT_BACKEND_CUPS (object); - if (backend_cups->list_printers_poll > 0) - g_source_remove (backend_cups->list_printers_poll); - - if (backend_cups->printers) - g_hash_table_unref (backend_cups->printers); - g_free (backend_cups->default_printer); backend_cups->default_printer = NULL; backend_parent_class->finalize (object); } +static void +gtk_print_backend_cups_dispose (GObject *object) +{ + GtkPrintBackendCups *backend_cups; + + backend_cups = GTK_PRINT_BACKEND_CUPS (object); + + if (backend_cups->list_printers_poll > 0) + g_source_remove (backend_cups->list_printers_poll); + backend_cups->list_printers_poll = 0; + + backend_parent_class->dispose (object); +} + + static gboolean cups_dispatch_watch_check (GSource *source) { @@ -514,13 +502,12 @@ cups_dispatch_watch_check (GSource *source) static gboolean cups_dispatch_watch_prepare (GSource *source, - gint *timeout_) + gint *timeout_) { GtkPrintCupsDispatchWatch *dispatch; dispatch = (GtkPrintCupsDispatchWatch *) source; - *timeout_ = -1; return gtk_cups_request_read_write (dispatch->request); @@ -528,8 +515,8 @@ cups_dispatch_watch_prepare (GSource *source, static gboolean cups_dispatch_watch_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) + GSourceFunc callback, + gpointer user_data) { GtkPrintCupsDispatchWatch *dispatch; GtkPrintCupsResponseCallbackFunc ep_callback; @@ -548,7 +535,6 @@ cups_dispatch_watch_dispatch (GSource *source, ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data); - g_source_unref (source); return FALSE; } @@ -563,7 +549,11 @@ cups_dispatch_watch_finalize (GSource *source) if (dispatch->backend) { - g_object_unref (dispatch->backend); + /* We need to unref this at idle time, because it might be the + last reference to this module causing the code to be + unloaded (including this particular function!) + */ + gtk_print_backend_unref_at_idle (GTK_PRINT_BACKEND (dispatch->backend)); dispatch->backend = NULL; } @@ -588,7 +578,7 @@ cups_request_execute (GtkPrintBackendCups *print_backend, GError **err) { GtkPrintCupsDispatchWatch *dispatch; - + dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, sizeof (GtkPrintCupsDispatchWatch)); @@ -599,10 +589,11 @@ cups_request_execute (GtkPrintBackendCups *print_backend, g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify); g_source_attach ((GSource *) dispatch, NULL); + g_source_unref ((GSource *) dispatch); } static void -cups_request_printer_info_cb (GtkPrintBackendCups *print_backend, +cups_request_printer_info_cb (GtkPrintBackendCups *backend, GtkCupsResult *result, gpointer user_data) { @@ -611,40 +602,29 @@ cups_request_printer_info_cb (GtkPrintBackendCups *print_backend, gchar *printer_name; GtkPrinterCups *cups_printer; GtkPrinter *printer; - gchar *printer_uri; - gchar *member_printer_uri; gchar *loc; gchar *desc; gchar *state_msg; int job_count; - - char uri[HTTP_MAX_URI], /* Printer URI */ - method[HTTP_MAX_URI], /* Method/scheme name */ - username[HTTP_MAX_URI], /* Username:password */ - hostname[HTTP_MAX_URI], /* Hostname */ - resource[HTTP_MAX_URI]; /* Resource name */ - int port; /* Port number */ gboolean status_changed; - g_assert (GTK_IS_PRINT_BACKEND_CUPS (print_backend)); - - printer_uri = NULL; - member_printer_uri = NULL; + g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend)); printer_name = (gchar *)user_data; - cups_printer = (GtkPrinterCups *) g_hash_table_lookup (print_backend->printers, printer_name); + printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend), + printer_name); - if (!cups_printer) + if (!printer) return; - printer = GTK_PRINTER (cups_printer); + cups_printer = GTK_PRINTER_CUPS (printer); if (gtk_cups_result_is_error (result)) { if (gtk_printer_is_new (printer)) { - g_hash_table_remove (print_backend->printers, - printer_name); + gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend), + printer); return; } else @@ -656,8 +636,6 @@ cups_request_printer_info_cb (GtkPrintBackendCups *print_backend, /* TODO: determine printer type and use correct icon */ gtk_printer_set_icon_name (printer, "printer"); - cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name); - state_msg = ""; loc = ""; desc = ""; @@ -670,8 +648,6 @@ cups_request_printer_info_cb (GtkPrintBackendCups *print_backend, _CUPS_MAP_ATTR_STR (attr, loc, "printer-location"); _CUPS_MAP_ATTR_STR (attr, desc, "printer-info"); _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message"); - _CUPS_MAP_ATTR_STR (attr, printer_uri, "printer-uri-supported"); - _CUPS_MAP_ATTR_STR (attr, member_printer_uri, "member-uris"); _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state"); _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count"); } @@ -679,53 +655,15 @@ cups_request_printer_info_cb (GtkPrintBackendCups *print_backend, /* if we got a member_printer_uri then this printer is part of a class so use member_printer_uri, else user printer_uri */ - if (cups_printer->printer_uri) - g_free (cups_printer->printer_uri); - - if (member_printer_uri) - { - g_free (printer_uri); - cups_printer->printer_uri = member_printer_uri; - } - else - cups_printer->printer_uri = printer_uri; - status_changed = gtk_printer_set_job_count (printer, job_count); status_changed |= gtk_printer_set_location (printer, loc); status_changed |= gtk_printer_set_description (printer, desc); status_changed |= gtk_printer_set_state_message (printer, state_msg); -#if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1 - httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri, - method, sizeof (method), - username, sizeof (username), - hostname, sizeof (hostname), - &port, - resource, sizeof (resource)); - -#else - httpSeparate (cups_printer->printer_uri, - method, - username, - hostname, - &port, - resource); -#endif - - gethostname(uri, sizeof(uri)); - - if (strcasecmp(uri, hostname) == 0) - strcpy(hostname, "localhost"); - - if (cups_printer->hostname) - g_free (cups_printer->hostname); - - cups_printer->hostname = g_strdup (hostname); - cups_printer->port = port; - if (status_changed) - g_signal_emit_by_name (GTK_PRINT_BACKEND (print_backend), "printer-status-changed", printer); + g_signal_emit_by_name (GTK_PRINT_BACKEND (backend), + "printer-status-changed", printer); } static void @@ -735,6 +673,14 @@ cups_request_printer_info (GtkPrintBackendCups *print_backend, GError *error; GtkCupsRequest *request; gchar *printer_uri; + static const char * const pattrs[] = /* Attributes we're interested in */ + { + "printer-location", + "printer-info", + "printer-state-message", + "printer-state", + "queued-job-count" + }; error = NULL; @@ -752,6 +698,10 @@ cups_request_printer_info (GtkPrintBackendCups *print_backend, g_free (printer_uri); + gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", G_N_ELEMENTS (pattrs), + NULL, pattrs); + cups_request_execute (print_backend, request, (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb, @@ -922,82 +872,22 @@ cups_begin_polling_info (GtkPrintBackendCups *print_backend, cups_request_job_info (data); } -static gint -printer_cmp (GtkPrinter *a, GtkPrinter *b) -{ - const char *name_a, *name_b; - g_assert (GTK_IS_PRINTER (a) && GTK_IS_PRINTER (b)); - - name_a = gtk_printer_get_name (a); - name_b = gtk_printer_get_name (b); - if (name_a == NULL && name_b == NULL) - return 0; - else if (name_a == NULL) - return G_MAXINT; - else if (name_b == NULL) - return G_MININT; - else - return g_ascii_strcasecmp (name_a, name_b); -} - static void -printer_hash_to_sorted_active_list (const gchar *key, - gpointer value, - GList **out_list) +mark_printer_inactive (GtkPrinter *printer, + GtkPrintBackend *backend) { - GtkPrinter *printer; - - printer = GTK_PRINTER (value); - - if (gtk_printer_get_name (printer) == NULL) - return; - - if (!gtk_printer_is_active (printer)) - return; - - *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) printer_cmp); + gtk_printer_set_is_active (printer, FALSE); + g_signal_emit_by_name (backend, + "printer-removed", printer); } -static void -printer_hash_to_sorted_active_name_list (const gchar *key, - gpointer value, - GList **out_list) +static gint +find_printer (GtkPrinter *printer, const char *find_name) { - GtkPrinter *printer; - - printer = GTK_PRINTER (value); - - - if (gtk_printer_get_name (printer) == NULL) - return; - - if (!gtk_printer_is_active (printer)) - return; + const char *printer_name; - if (gtk_printer_is_active (printer)) - *out_list = g_list_insert_sorted (*out_list, - (char *)gtk_printer_get_name (printer), - g_str_equal); -} - -static void -mark_printer_inactive (const gchar *printer_name, - GtkPrintBackendCups *cups_backend) -{ - GtkPrinter *printer; - GHashTable *printer_hash; - - printer_hash = cups_backend->printers; - - printer = (GtkPrinter *) g_hash_table_lookup (printer_hash, - printer_name); - - if (printer == NULL) - return; - - gtk_printer_set_is_active (printer, FALSE); - - g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-removed", printer); + printer_name = gtk_printer_get_name (printer); + return g_ascii_strcasecmp (printer_name, find_name); } static void @@ -1021,51 +911,122 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result)); return; } - + /* gether the names of the printers in the current queue so we may check to see if they were removed */ - removed_printer_checklist = NULL; - if (cups_backend->printers != NULL) - g_hash_table_foreach (cups_backend->printers, - (GHFunc) printer_hash_to_sorted_active_name_list, - &removed_printer_checklist); - + removed_printer_checklist = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (cups_backend)); + response = gtk_cups_result_get_response (result); - attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME); - while (attr) + for (attr = response->attrs; attr != NULL; attr = attr->next) { - GtkPrinterCups *cups_printer; GtkPrinter *printer; const gchar *printer_name; + const char *printer_uri; + const char *member_uris; GList *node; + + /* + * Skip leading attributes until we hit a printer... + */ + while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; + + if (attr == NULL) + break; + + printer_name = NULL; + printer_uri = NULL; + member_uris = NULL; + while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) + { + if (!strcmp(attr->name, "printer-name") && + attr->value_tag == IPP_TAG_NAME) + printer_name = attr->values[0].string.text; + else if (!strcmp(attr->name, "printer-uri-supported") && + attr->value_tag == IPP_TAG_URI) + printer_uri = attr->values[0].string.text; + else if (!strcmp(attr->name, "member-uris") && + attr->value_tag == IPP_TAG_URI) + member_uris = attr->values[0].string.text; + + attr = attr->next; + } - printer_name = attr->values[0].string.text; + if (printer_name == NULL || + (printer_uri == NULL && member_uris == NULL)) + { + if (attr == NULL) + break; + else + continue; + } + /* remove name from checklist if it was found */ - node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) g_ascii_strcasecmp); + node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer); removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node); - cups_printer = (GtkPrinterCups *) g_hash_table_lookup (cups_backend->printers, - printer_name); - printer = cups_printer ? GTK_PRINTER (cups_printer) : NULL; - - if (!cups_printer) + printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), printer_name); + if (!printer) { + GtkPrinterCups *cups_printer; + char uri[HTTP_MAX_URI], /* Printer URI */ + method[HTTP_MAX_URI], /* Method/scheme name */ + username[HTTP_MAX_URI], /* Username:password */ + hostname[HTTP_MAX_URI], /* Hostname */ + resource[HTTP_MAX_URI]; /* Resource name */ + int port; /* Port number */ + list_has_changed = TRUE; - cups_printer = gtk_printer_cups_new (attr->values[0].string.text, + cups_printer = gtk_printer_cups_new (printer_name, GTK_PRINT_BACKEND (cups_backend)); - printer = GTK_PRINTER (cups_printer); + cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name); + + if (member_uris) + { + cups_printer->printer_uri = g_strdup (member_uris); + } + else + cups_printer->printer_uri = g_strdup (printer_uri); + +#if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1 + httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri, + method, sizeof (method), + username, sizeof (username), + hostname, sizeof (hostname), + &port, + resource, sizeof (resource)); + +#else + httpSeparate (cups_printer->printer_uri, + method, + username, + hostname, + &port, + resource); +#endif + + gethostname(uri, sizeof(uri)); + if (strcasecmp(uri, hostname) == 0) + strcpy(hostname, "localhost"); + + cups_printer->hostname = g_strdup (hostname); + cups_printer->port = port; + + printer = GTK_PRINTER (cups_printer); + if (cups_backend->default_printer != NULL && strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0) gtk_printer_set_is_default (printer, TRUE); - g_hash_table_insert (cups_backend->printers, - g_strdup (gtk_printer_get_name (printer)), - cups_printer); + + gtk_print_backend_add_printer (GTK_PRINT_BACKEND (cups_backend), printer); } - + else + g_object_ref (printer); + if (!gtk_printer_is_active (printer)) { gtk_printer_set_is_active (printer, TRUE); @@ -1083,25 +1044,29 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, } cups_request_printer_info (cups_backend, gtk_printer_get_name (printer)); - - attr = ippFindNextAttribute (response, - "printer-name", - IPP_TAG_NAME); - } - /* look at the removed printers checklist and mark any printer - as inactive if it is in the list, emitting a printer_removed signal */ + /* The ref is held by GtkPrintBackend, in add_printer() */ + g_object_unref (printer); - if (removed_printer_checklist != NULL) - { - g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, cups_backend); - g_list_free (removed_printer_checklist); - list_has_changed = TRUE; - } - - if (list_has_changed) - g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed"); + + if (attr == NULL) + break; + } + /* look at the removed printers checklist and mark any printer + as inactive if it is in the list, emitting a printer_removed signal */ + if (removed_printer_checklist != NULL) + { + g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, + GTK_PRINT_BACKEND (cups_backend)); + g_list_free (removed_printer_checklist); + list_has_changed = TRUE; + } + + if (list_has_changed) + g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed"); + + gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (cups_backend)); } static gboolean @@ -1109,7 +1074,13 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend) { GError *error; GtkCupsRequest *request; - + static const char * const pattrs[] = /* Attributes we're interested in */ + { + "printer-name", + "printer-uri-supported", + "member-uris" + }; + if (cups_backend->list_printers_pending || !cups_backend->got_default_printer) return TRUE; @@ -1125,6 +1096,10 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend) NULL, NULL); + gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", G_N_ELEMENTS (pattrs), + NULL, pattrs); + cups_request_execute (cups_backend, request, (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb, @@ -1136,29 +1111,19 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend) return TRUE; } -static GList * -cups_get_printer_list (GtkPrintBackend *print_backend) +static void +cups_get_printer_list (GtkPrintBackend *backend) { GtkPrintBackendCups *cups_backend; - GList *result; - - cups_backend = GTK_PRINT_BACKEND_CUPS (print_backend); - - result = NULL; - if (cups_backend->printers != NULL) - g_hash_table_foreach (cups_backend->printers, - (GHFunc) printer_hash_to_sorted_active_list, - &result); + cups_backend = GTK_PRINT_BACKEND_CUPS (backend); if (cups_backend->list_printers_poll == 0) { cups_request_printer_list (cups_backend); - cups_backend->list_printers_poll = g_timeout_add (3000, + cups_backend->list_printers_poll = g_timeout_add (3000 * 100000, (GSourceFunc) cups_request_printer_list, - print_backend); + backend); } - - return result; } typedef struct { diff --git a/modules/printbackends/cups/gtkprintercups.c b/modules/printbackends/cups/gtkprintercups.c index c36b8077e5..89713339e7 100644 --- a/modules/printbackends/cups/gtkprintercups.c +++ b/modules/printbackends/cups/gtkprintercups.c @@ -90,8 +90,7 @@ gtk_printer_cups_finalize (GObject *object) if (printer->ppd_file) ppdClose (printer->ppd_file); - if (G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize) - G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize (object); + G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize (object); } /** diff --git a/modules/printbackends/lpr/gtkprintbackendlpr.c b/modules/printbackends/lpr/gtkprintbackendlpr.c index 4560c92a2f..daed2e589b 100644 --- a/modules/printbackends/lpr/gtkprintbackendlpr.c +++ b/modules/printbackends/lpr/gtkprintbackendlpr.c @@ -51,25 +51,18 @@ static GType print_backend_lpr_type = 0; struct _GtkPrintBackendLprClass { - GObjectClass parent_class; + GtkPrintBackendClass parent_class; }; struct _GtkPrintBackendLpr { - GObject parent_instance; - - GtkPrinter *printer; - - GHashTable *printers; + GtkPrintBackend parent_instance; }; static GObjectClass *backend_parent_class; static void gtk_print_backend_lpr_class_init (GtkPrintBackendLprClass *class); -static void gtk_print_backend_lpr_iface_init (GtkPrintBackendIface *iface); static void gtk_print_backend_lpr_init (GtkPrintBackendLpr *impl); -static void gtk_print_backend_lpr_finalize (GObject *object); -static GList * lpr_request_printer_list (GtkPrintBackend *print_backend); static void lpr_printer_get_settings_from_options (GtkPrinter *printer, GtkPrinterOptionSet *options, GtkPrintSettings *settings); @@ -89,6 +82,16 @@ static void lpr_printer_get_hard_margins (GtkPrinter double *right); static void lpr_printer_request_details (GtkPrinter *printer); static GList * lpr_printer_list_papers (GtkPrinter *printer); +static cairo_surface_t * lpr_printer_create_cairo_surface (GtkPrinter *printer, + gdouble width, + gdouble height, + gint cache_fd); +static void gtk_print_backend_lpr_print_stream (GtkPrintBackend *print_backend, + GtkPrintJob *job, + gint data_fd, + GtkPrintJobCompleteFunc callback, + gpointer user_data, + GDestroyNotify dnotify); static void gtk_print_backend_lpr_register_type (GTypeModule *module) @@ -108,24 +111,11 @@ gtk_print_backend_lpr_register_type (GTypeModule *module) (GInstanceInitFunc) gtk_print_backend_lpr_init, }; - static const GInterfaceInfo print_backend_info = - { - (GInterfaceInitFunc) gtk_print_backend_lpr_iface_init, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - print_backend_lpr_type = g_type_module_register_type (module, - G_TYPE_OBJECT, - "GtkPrintBackendLpr", - &print_backend_lpr_info, 0); - g_type_module_add_interface (module, - print_backend_lpr_type, - GTK_TYPE_PRINT_BACKEND, - &print_backend_info); + GTK_TYPE_PRINT_BACKEND, + "GtkPrintBackendLpr", + &print_backend_lpr_info, 0); } - - } G_MODULE_EXPORT void @@ -173,11 +163,19 @@ gtk_print_backend_lpr_new (void) static void gtk_print_backend_lpr_class_init (GtkPrintBackendLprClass *class) { - GObjectClass *gobject_class = G_OBJECT_CLASS (class); - + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class); + backend_parent_class = g_type_class_peek_parent (class); - gobject_class->finalize = gtk_print_backend_lpr_finalize; + backend_class->print_stream = gtk_print_backend_lpr_print_stream; + backend_class->printer_request_details = lpr_printer_request_details; + backend_class->printer_create_cairo_surface = lpr_printer_create_cairo_surface; + backend_class->printer_get_options = lpr_printer_get_options; + backend_class->printer_mark_conflicts = lpr_printer_mark_conflicts; + backend_class->printer_get_settings_from_options = lpr_printer_get_settings_from_options; + backend_class->printer_prepare_for_print = lpr_printer_prepare_for_print; + backend_class->printer_list_papers = lpr_printer_list_papers; + backend_class->printer_get_hard_margins = lpr_printer_get_hard_margins; } static cairo_status_t @@ -215,22 +213,6 @@ lpr_printer_create_cairo_surface (GtkPrinter *printer, return surface; } -static GtkPrinter * -gtk_print_backend_lpr_find_printer (GtkPrintBackend *print_backend, - const gchar *printer_name) -{ - GtkPrintBackendLpr *lpr_print_backend; - GtkPrinter *printer; - - lpr_print_backend = GTK_PRINT_BACKEND_LPR (print_backend); - - printer = NULL; - if (strcmp (gtk_printer_get_name (lpr_print_backend->printer), printer_name) == 0) - printer = lpr_print_backend->printer; - - return printer; -} - typedef struct { GtkPrintBackend *backend; GtkPrintJobCompleteFunc callback; @@ -398,64 +380,21 @@ gtk_print_backend_lpr_print_stream (GtkPrintBackend *print_backend, g_strfreev (argv); } - static void -gtk_print_backend_lpr_iface_init (GtkPrintBackendIface *iface) -{ - iface->get_printer_list = lpr_request_printer_list; - iface->find_printer = gtk_print_backend_lpr_find_printer; - iface->print_stream = gtk_print_backend_lpr_print_stream; - iface->printer_request_details = lpr_printer_request_details; - iface->printer_create_cairo_surface = lpr_printer_create_cairo_surface; - iface->printer_get_options = lpr_printer_get_options; - iface->printer_mark_conflicts = lpr_printer_mark_conflicts; - iface->printer_get_settings_from_options = lpr_printer_get_settings_from_options; - iface->printer_prepare_for_print = lpr_printer_prepare_for_print; - iface->printer_list_papers = lpr_printer_list_papers; - iface->printer_get_hard_margins = lpr_printer_get_hard_margins; -} - -static GList * -lpr_request_printer_list (GtkPrintBackend *backend) -{ - GList *l; - GtkPrintBackendLpr *lpr_backend; - - l = NULL; - - lpr_backend = GTK_PRINT_BACKEND_LPR (backend); - - if (lpr_backend->printer) - l = g_list_append (l, lpr_backend->printer); - - return l; -} - -static void -gtk_print_backend_lpr_init (GtkPrintBackendLpr *backend_lpr) +gtk_print_backend_lpr_init (GtkPrintBackendLpr *backend) { GtkPrinter *printer; printer = gtk_printer_new (_("Print to LPR"), - GTK_PRINT_BACKEND (backend_lpr), + GTK_PRINT_BACKEND (backend), TRUE); gtk_printer_set_has_details (printer, TRUE); gtk_printer_set_icon_name (printer, "printer"); gtk_printer_set_is_active (printer, TRUE); - - backend_lpr->printer = printer; -} - -static void -gtk_print_backend_lpr_finalize (GObject *object) -{ - GtkPrintBackendLpr *backend_lpr; - - backend_lpr = GTK_PRINT_BACKEND_LPR (object); - - g_object_unref (backend_lpr->printer); + gtk_printer_set_is_default (printer, TRUE); - backend_parent_class->finalize (object); + gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer); + g_object_unref (printer); } static void diff --git a/modules/printbackends/pdf/gtkprintbackendpdf.c b/modules/printbackends/pdf/gtkprintbackendpdf.c index e746f92d46..206b2c1a8e 100644 --- a/modules/printbackends/pdf/gtkprintbackendpdf.c +++ b/modules/printbackends/pdf/gtkprintbackendpdf.c @@ -52,25 +52,18 @@ static GType print_backend_pdf_type = 0; struct _GtkPrintBackendPdfClass { - GObjectClass parent_class; + GtkPrintBackendClass parent_class; }; struct _GtkPrintBackendPdf { - GObject parent_instance; - - GtkPrinter *printer; - - GHashTable *printers; + GtkPrintBackend parent_instance; }; static GObjectClass *backend_parent_class; static void gtk_print_backend_pdf_class_init (GtkPrintBackendPdfClass *class); -static void gtk_print_backend_pdf_iface_init (GtkPrintBackendIface *iface); static void gtk_print_backend_pdf_init (GtkPrintBackendPdf *impl); -static void gtk_print_backend_pdf_finalize (GObject *object); -static GList * pdf_request_printer_list (GtkPrintBackend *print_backend); static void pdf_printer_get_settings_from_options (GtkPrinter *printer, GtkPrinterOptionSet *options, GtkPrintSettings *settings); @@ -90,6 +83,16 @@ static void pdf_printer_get_hard_margins (GtkPrinter double *right); static void pdf_printer_request_details (GtkPrinter *printer); static GList * pdf_printer_list_papers (GtkPrinter *printer); +static void gtk_print_backend_pdf_print_stream (GtkPrintBackend *print_backend, + GtkPrintJob *job, + gint data_fd, + GtkPrintJobCompleteFunc callback, + gpointer user_data, + GDestroyNotify dnotify); +static cairo_surface_t * pdf_printer_create_cairo_surface (GtkPrinter *printer, + gdouble width, + gdouble height, + gint cache_fd); static void gtk_print_backend_pdf_register_type (GTypeModule *module) @@ -109,24 +112,11 @@ gtk_print_backend_pdf_register_type (GTypeModule *module) (GInstanceInitFunc) gtk_print_backend_pdf_init, }; - static const GInterfaceInfo print_backend_info = - { - (GInterfaceInitFunc) gtk_print_backend_pdf_iface_init, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - print_backend_pdf_type = g_type_module_register_type (module, - G_TYPE_OBJECT, - "GtkPrintBackendPdf", - &print_backend_pdf_info, 0); - g_type_module_add_interface (module, - print_backend_pdf_type, - GTK_TYPE_PRINT_BACKEND, - &print_backend_info); + GTK_TYPE_PRINT_BACKEND, + "GtkPrintBackendPdf", + &print_backend_pdf_info, 0); } - - } G_MODULE_EXPORT void @@ -174,11 +164,19 @@ gtk_print_backend_pdf_new (void) static void gtk_print_backend_pdf_class_init (GtkPrintBackendPdfClass *class) { - GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class); backend_parent_class = g_type_class_peek_parent (class); - gobject_class->finalize = gtk_print_backend_pdf_finalize; + backend_class->print_stream = gtk_print_backend_pdf_print_stream; + backend_class->printer_request_details = pdf_printer_request_details; + backend_class->printer_create_cairo_surface = pdf_printer_create_cairo_surface; + backend_class->printer_get_options = pdf_printer_get_options; + backend_class->printer_mark_conflicts = pdf_printer_mark_conflicts; + backend_class->printer_get_settings_from_options = pdf_printer_get_settings_from_options; + backend_class->printer_prepare_for_print = pdf_printer_prepare_for_print; + backend_class->printer_list_papers = pdf_printer_list_papers; + backend_class->printer_get_hard_margins = pdf_printer_get_hard_margins; } static cairo_status_t @@ -216,22 +214,6 @@ pdf_printer_create_cairo_surface (GtkPrinter *printer, return surface; } -static GtkPrinter * -gtk_print_backend_pdf_find_printer (GtkPrintBackend *print_backend, - const gchar *printer_name) -{ - GtkPrintBackendPdf *pdf_print_backend; - GtkPrinter *printer; - - pdf_print_backend = GTK_PRINT_BACKEND_PDF (print_backend); - - printer = NULL; - if (strcmp (gtk_printer_get_name (pdf_print_backend->printer), printer_name) == 0) - printer = pdf_print_backend->printer; - - return printer; -} - typedef struct { GtkPrintBackend *backend; GtkPrintJobCompleteFunc callback; @@ -366,64 +348,23 @@ gtk_print_backend_pdf_print_stream (GtkPrintBackend *print_backend, ps); } - static void -gtk_print_backend_pdf_iface_init (GtkPrintBackendIface *iface) -{ - iface->get_printer_list = pdf_request_printer_list; - iface->find_printer = gtk_print_backend_pdf_find_printer; - iface->print_stream = gtk_print_backend_pdf_print_stream; - iface->printer_request_details = pdf_printer_request_details; - iface->printer_create_cairo_surface = pdf_printer_create_cairo_surface; - iface->printer_get_options = pdf_printer_get_options; - iface->printer_mark_conflicts = pdf_printer_mark_conflicts; - iface->printer_get_settings_from_options = pdf_printer_get_settings_from_options; - iface->printer_prepare_for_print = pdf_printer_prepare_for_print; - iface->printer_list_papers = pdf_printer_list_papers; - iface->printer_get_hard_margins = pdf_printer_get_hard_margins; -} - -static GList * -pdf_request_printer_list (GtkPrintBackend *backend) -{ - GList *l; - GtkPrintBackendPdf *pdf_backend; - - l = NULL; - - pdf_backend = GTK_PRINT_BACKEND_PDF (backend); - - if (pdf_backend->printer) - l = g_list_append (l, pdf_backend->printer); - - return l; -} - -static void -gtk_print_backend_pdf_init (GtkPrintBackendPdf *backend_pdf) +gtk_print_backend_pdf_init (GtkPrintBackendPdf *backend) { GtkPrinter *printer; - backend_pdf->printer = gtk_printer_new (_("Print to PDF"), - GTK_PRINT_BACKEND (backend_pdf), - TRUE); + printer = gtk_printer_new (_("Print to PDF"), + GTK_PRINT_BACKEND (backend), + TRUE); - printer = backend_pdf->printer; gtk_printer_set_has_details (printer, TRUE); gtk_printer_set_icon_name (printer, "floppy"); gtk_printer_set_is_active (printer, TRUE); -} - -static void -gtk_print_backend_pdf_finalize (GObject *object) -{ - GtkPrintBackendPdf *backend_pdf; - - backend_pdf = GTK_PRINT_BACKEND_PDF (object); - g_object_unref (backend_pdf->printer); + gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer); + g_object_unref (printer); - backend_parent_class->finalize (object); + gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (backend)); } static void diff --git a/tests/Makefile.am b/tests/Makefile.am index a900f8d5fb..c5d269ec42 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -53,6 +53,7 @@ noinst_PROGRAMS = \ testmultidisplay \ testmultiscreen \ testnotebookdnd \ + testnouiprint \ testrgb \ testrecentchooser \ testselection \ @@ -107,6 +108,7 @@ testmenubars_DEPENDENCIES = $(TEST_DEPS) testmultidisplay_DEPENDENCIES = $(TEST_DEPS) testmultiscreen_DEPENDENCIES = $(TEST_DEPS) testnotebookdnd_DEPENDENCIES = $(TEST_DEPS) +testnouiprint_DEPENDENCIES = $(TEST_DEPS) testrecentchooser_DEPENDENCIES = $(TEST_DEPS) testrgb_DEPENDENCIES = $(TEST_DEPS) testselection_DEPENDENCIES = $(TEST_DEPS) @@ -155,6 +157,7 @@ testmenubars_LDADD = $(LDADDS) testmultidisplay_LDADD = $(LDADDS) testmultiscreen_LDADD = $(LDADDS) testnotebookdnd_LDADD = $(LDADDS) +testnouiprint_LDADD = $(LDADDS) testrecentchooser_LDADD = $(LDADDS) testrgb_LDADD = $(LDADDS) testselection_LDADD = $(LDADDS) diff --git a/tests/testnouiprint.c b/tests/testnouiprint.c new file mode 100644 index 0000000000..3b0825b2ab --- /dev/null +++ b/tests/testnouiprint.c @@ -0,0 +1,107 @@ +/* -*- Mode: C; c-basic-offset: 2; -*- */ +/* Gtk+ - non-ui printing + * + * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "gtk/gtkprintoperation.h" +#include <math.h> + +static void +draw_page (GtkPrintOperation *operation, + GtkPrintContext *context, + int page_nr) +{ + cairo_t *cr; + PangoLayout *layout; + PangoFontDescription *desc; + + cr = gtk_print_context_get_cairo (context); + + /* Draw a red rectangle, as wide as the paper (inside the margins) */ + cairo_set_source_rgb (cr, 1.0, 0, 0); + cairo_rectangle (cr, 0, 0, gtk_print_context_get_width (context), 50); + + cairo_fill (cr); + + /* Draw some lines */ + cairo_move_to (cr, 20, 10); + cairo_line_to (cr, 40, 20); + cairo_arc (cr, 60, 60, 20, 0, M_PI); + cairo_line_to (cr, 80, 20); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 5); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + + cairo_stroke (cr); + + /* Draw some text */ + + layout = gtk_print_context_create_layout (context); + pango_layout_set_text (layout, "Hello World! Printing is easy", -1); + desc = pango_font_description_from_string ("sans 28"); + pango_layout_set_font_description (layout, desc); + pango_font_description_free (desc); + + cairo_move_to (cr, 30, 20); + pango_cairo_layout_path (cr, layout); + + /* Font Outline */ + cairo_set_source_rgb (cr, 0.93, 1.0, 0.47); + cairo_set_line_width (cr, 0.5); + cairo_stroke_preserve (cr); + + /* Font Fill */ + cairo_set_source_rgb (cr, 0, 0.0, 1.0); + cairo_fill (cr); + + g_object_unref (layout); +} + + +int +main (int argc, char **argv) +{ + GMainLoop *loop; + GtkPrintOperation *print; + GtkPrintOperationResult res; + GtkPrintSettings *settings; + + + /* Unfortunately we need a display for the XSettings to get the + list of backends... */ + /* gtk_parse_args (&argc, &argv); */ + gtk_init (&argc, &argv); + + loop = g_main_loop_new (NULL, TRUE); + + settings = gtk_print_settings_new (); + /* gtk_print_settings_set_printer (settings, "printer"); */ + + print = gtk_print_operation_new (); + gtk_print_operation_set_print_settings (print, settings); + gtk_print_operation_set_nr_of_pages (print, 1); + gtk_print_operation_set_unit (print, GTK_UNIT_MM); + gtk_print_operation_set_show_dialog (print, FALSE); + g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), NULL); + res = gtk_print_operation_run (print, NULL, NULL); + + return 0; +} |