diff --git a/configure.ac b/configure.ac index 4e0fb6f480..77a6cee5c7 100644 --- a/configure.ac +++ b/configure.ac @@ -1532,6 +1532,27 @@ fi AM_CONDITIONAL(ENABLE_PACKAGEKIT, test "x$build_packagekit" = "xyes") +################################################## +# colord module +################################################# + +AC_ARG_ENABLE(colord, + [AS_HELP_STRING([--disable-colord], + [build colord support code])]) + +have_colord=no +if test "x$enable_colord" != "xno"; then + if test "os_win32" != "yes"; then + PKG_CHECK_MODULES(COLORD, colord >= 0.1.9) + have_colord=yes + AC_DEFINE(HAVE_COLORD, 1, [define if we have colord]) + else + AC_MSG_ERROR([colord support is not available on win32]) + fi +fi + +AM_CONDITIONAL(HAVE_COLORD, test "x$have_colord" = "xyes") + ################################################## # Checks for gtk-doc and docbook-tools ################################################## @@ -1723,6 +1744,7 @@ echo " Print backends: $PRINT_BACKENDS" echo " Dynamic modules: $build_dynamic_modules" echo " Included immodules: $included_immodules" echo " PackageKit support: $build_packagekit" +echo " colord support: $have_colord" echo " Introspection: $found_introspection" echo " Debugging: $enable_debug" echo " Documentation: $enable_gtk_doc" diff --git a/modules/printbackends/cups/Makefile.am b/modules/printbackends/cups/Makefile.am index c04fa46649..665657a4c1 100644 --- a/modules/printbackends/cups/Makefile.am +++ b/modules/printbackends/cups/Makefile.am @@ -11,12 +11,14 @@ INCLUDES = \ -I$(top_srcdir)/gdk \ -I$(top_builddir)/gdk \ $(CUPS_CFLAGS) \ + $(COLORD_CFLAGS) \ -DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED \ $(GTK_DEP_CFLAGS) \ $(GTK_DEBUG_FLAGS) LDADDS = \ $(top_builddir)/gtk/libgtk-3.la \ + $(COLORD_LIBS) \ $(GTK_DEP_LIBS) backenddir = $(libdir)/gtk-3.0/$(GTK_BINARY_VERSION)/printbackends diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index 2e1e1a9da8..c7bcd6f991 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -54,6 +54,9 @@ #include "gtkcupsutils.h" +#ifdef HAVE_COLORD +#include +#endif typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass; @@ -125,6 +128,9 @@ struct _GtkPrintBackendCups GHashTable *auth; gchar *username; gboolean authentication_lock; +#ifdef HAVE_COLORD + CdClient *colord_client; +#endif }; static GObjectClass *backend_parent_class; @@ -607,6 +613,10 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups) backend_cups->username = NULL; +#ifdef HAVE_COLORD + backend_cups->colord_client = cd_client_new (); +#endif + cups_get_local_default_printer (backend_cups); } @@ -633,6 +643,10 @@ gtk_print_backend_cups_finalize (GObject *object) g_free (backend_cups->username); +#ifdef HAVE_COLORD + g_object_unref (backend_cups->colord_client); +#endif + backend_parent_class->finalize (object); } @@ -1882,7 +1896,13 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, char *cups_server; /* CUPS server */ list_has_changed = TRUE; - cups_printer = gtk_printer_cups_new (printer_name, backend); +#ifdef HAVE_COLORD + cups_printer = gtk_printer_cups_new (printer_name, + backend, + cups_backend->colord_client); +#else + cups_printer = gtk_printer_cups_new (printer_name, backend, NULL); +#endif cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name); @@ -3511,6 +3531,23 @@ handle_group (GtkPrinterOptionSet *set, } +#ifdef HAVE_COLORD + +typedef struct { + GtkPrintSettings *settings; + GtkPrinter *printer; +} GtkPrintBackendCupsColordHelper; + +static void +colord_printer_option_set_changed_cb (GtkPrinterOptionSet *set, + GtkPrintBackendCupsColordHelper *helper) +{ + gtk_printer_cups_update_settings (GTK_PRINTER_CUPS (helper->printer), + helper->settings, + set); +} +#endif + static GtkPrinterOptionSet * cups_printer_get_options (GtkPrinter *printer, GtkPrintSettings *settings, @@ -3542,7 +3579,9 @@ cups_printer_get_options (GtkPrinter *printer, GtkPrintBackendCups *backend; GtkTextDirection text_direction; GtkPrinterCups *cups_printer = NULL; - +#ifdef HAVE_COLORD + GtkPrintBackendCupsColordHelper *helper; +#endif set = gtk_printer_option_set_new (); @@ -3808,6 +3847,38 @@ cups_printer_get_options (GtkPrinter *printer, cupsFreeOptions (num_opts, opts); +#ifdef HAVE_COLORD + /* TRANSLATORS: this this the ICC color profile to use for this job */ + option = gtk_printer_option_new ("colord-profile", + _("Printer Profile"), + GTK_PRINTER_OPTION_TYPE_INFO); + + /* assign it to the color page */ + option->group = g_strdup ("ColorPage"); + + /* TRANSLATORS: this is when color profile information is unavailable */ + gtk_printer_option_set (option, _("Unavailable")); + gtk_printer_option_set_add (set, option); + + /* watch to see if the user changed the options */ + helper = g_new (GtkPrintBackendCupsColordHelper, 1); + helper->printer = printer; + helper->settings = settings; + g_signal_connect_data (set, "changed", + G_CALLBACK (colord_printer_option_set_changed_cb), + helper, + (GClosureNotify) g_free, + 0); + + /* initial coldplug */ + gtk_printer_cups_update_settings (GTK_PRINTER_CUPS (printer), + settings, set); + g_object_bind_property (printer, "profile-title", + option, "value", + G_BINDING_DEFAULT); + +#endif + return set; } diff --git a/modules/printbackends/cups/gtkprintercups.c b/modules/printbackends/cups/gtkprintercups.c index 8b3f85c06a..3ed44ae41d 100644 --- a/modules/printbackends/cups/gtkprintercups.c +++ b/modules/printbackends/cups/gtkprintercups.c @@ -1,5 +1,6 @@ /* GtkPrinterCupsCups * Copyright (C) 2006 John (J5) Palmieri + * Copyright (C) 2011 Richard Hughes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,8 +19,21 @@ */ #include "config.h" + +#include + +#ifdef HAVE_COLORD +#include +#endif + +#include "gtkintl.h" #include "gtkprintercups.h" +enum { + PROP_0, + PROP_PROFILE_TITLE +}; + static void gtk_printer_cups_init (GtkPrinterCups *printer); static void gtk_printer_cups_class_init (GtkPrinterCupsClass *class); static void gtk_printer_cups_finalize (GObject *object); @@ -27,6 +41,15 @@ static void gtk_printer_cups_finalize (GObject *object); static GtkPrinterClass *gtk_printer_cups_parent_class; static GType gtk_printer_cups_type = 0; +static void gtk_printer_cups_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_printer_cups_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + void gtk_printer_cups_register_type (GTypeModule *module) { @@ -59,10 +82,20 @@ static void gtk_printer_cups_class_init (GtkPrinterCupsClass *class) { GObjectClass *object_class = (GObjectClass *) class; - - gtk_printer_cups_parent_class = g_type_class_peek_parent (class); object_class->finalize = gtk_printer_cups_finalize; + object_class->set_property = gtk_printer_cups_set_property; + object_class->get_property = gtk_printer_cups_get_property; + + gtk_printer_cups_parent_class = g_type_class_peek_parent (class); + + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_PROFILE_TITLE, + g_param_spec_string ("profile-title", + P_("Color Profile Title"), + P_("The title of the color profile to use"), + "", + G_PARAM_READABLE)); } static void @@ -101,6 +134,19 @@ gtk_printer_cups_finalize (GObject *object) g_free (printer->default_cover_after); g_strfreev (printer->auth_info_required); +#ifdef HAVE_COLORD + g_cancellable_cancel (printer->colord_cancellable); + g_object_unref (printer->colord_cancellable); + g_free (printer->colord_title); + g_free (printer->colord_qualifier); + if (printer->colord_client) + g_object_unref (printer->colord_client); + if (printer->colord_device) + g_object_unref (printer->colord_device); + if (printer->colord_profile) + g_object_unref (printer->colord_profile); +#endif + if (printer->ppd_file) ppdClose (printer->ppd_file); @@ -113,6 +159,341 @@ gtk_printer_cups_finalize (GObject *object) G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize (object); } +static void +gtk_printer_cups_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_printer_cups_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkPrinterCups *printer = GTK_PRINTER_CUPS (object); + + switch (prop_id) + { + case PROP_PROFILE_TITLE: +#ifdef HAVE_COLORD + if (printer->colord_title) + g_value_set_string (value, printer->colord_title); + else + g_value_set_static_string (value, ""); +#else + g_value_set_static_string (value, NULL); +#endif + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +#ifdef HAVE_COLORD + +static void +colord_update_ui_from_settings (GtkPrinterCups *printer) +{ + const gchar *title = NULL; + + /* not yet connected to colord */ + if (printer->colord_client == NULL) + goto out; + if (!cd_client_get_connected (printer->colord_client)) + goto out; + + /* failed to get a colord device for the printer */ + if (printer->colord_device == NULL) + { + /* TRANSLATORS: when we're running an old CUPS, and + * it hasn't registered the device with colord */ + title = _("Color management unavailable"); + goto out; + } + + /* when colord prevents us from connecting (should not happen) */ + if (!cd_device_get_connected (printer->colord_device)) + goto out; + + /* failed to get a colord device for the printer */ + if (printer->colord_profile == NULL) + { + /* TRANSLATORS: when there is no color profile available */ + title = _("No profile available"); + goto out; + } + + /* when colord prevents us from connecting (should not happen) */ + if (!cd_profile_get_connected (printer->colord_profile)) + goto out; + title = cd_profile_get_title (printer->colord_profile); + if (title == NULL) + { + /* TRANSLATORS: when the color profile has no title */ + title = _("Unspecified profile"); + goto out; + } + +out: + /* SUCCESS! */ + if (g_strcmp0 (title, printer->colord_title) != 0) + { + g_free (printer->colord_title); + printer->colord_title = g_strdup (title); + g_object_notify (G_OBJECT (printer), "profile-title"); + } + return; +} + +static void +colord_client_profile_connect_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean ret; + GError *error = NULL; + GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data); + + ret = cd_profile_connect_finish (CD_PROFILE (source_object), + res, + &error); + if (!ret) + { + g_warning ("failed to get properties from the profile: %s", + error->message); + g_error_free (error); + } + + /* update the UI */ + colord_update_ui_from_settings (printer); +} + +static void +colord_client_device_get_profile_for_qualifiers_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data); + GError *error = NULL; + + printer->colord_profile = cd_device_get_profile_for_qualifiers_finish (printer->colord_device, + res, + &error); + if (printer->colord_profile == NULL) + { + /* not having a profile for a qualifier is not a warning */ + g_debug ("no profile for device %s: %s", + cd_device_get_id (printer->colord_device), + error->message); + g_error_free (error); + goto out; + } + + /* get details about the profile */ + cd_profile_connect (printer->colord_profile, + printer->colord_cancellable, + colord_client_profile_connect_cb, + printer); +out: + /* update the UI */ + colord_update_ui_from_settings (printer); +} + +void +gtk_printer_cups_update_settings (GtkPrinterCups *printer, + GtkPrintSettings *settings, + GtkPrinterOptionSet *set) +{ + gchar *qualifier = NULL; + gchar **qualifiers = NULL; + GtkPrinterOption *option; + const gchar *format[3]; + + /* nothing set yet */ + if (printer->colord_device == NULL) + goto out; + if (!cd_device_get_connected (printer->colord_device)) + goto out; + + /* cupsICCQualifier1 */ + option = gtk_printer_option_set_lookup (set, "cups-ColorSpace"); + if (option == NULL) + option = gtk_printer_option_set_lookup (set, "cups-ColorModel"); + if (option != NULL) + format[0] = option->value; + else + format[0] = "*"; + + /* cupsICCQualifier2 */ + option = gtk_printer_option_set_lookup (set, "cups-OutputMode"); + if (option != NULL) + format[1] = option->value; + else + format[1] = "*"; + + /* cupsICCQualifier3 */ + option = gtk_printer_option_set_lookup (set, "cups-Resolution"); + if (option != NULL) + format[2] = "*"; + + /* get profile for the device given the qualifier */ + qualifier = g_strdup_printf ("%s.%s.%s,%s.%s.*,%s.*.*", + format[0], format[1], format[2], + format[0], format[1], + format[0]); + + /* only requery colord if the option that was changed would give + * us a different profile result */ + if (g_strcmp0 (qualifier, printer->colord_qualifier) == 0) + goto out; + + qualifiers = g_strsplit (qualifier, ",", -1); + cd_device_get_profile_for_qualifiers (printer->colord_device, + (const gchar **) qualifiers, + printer->colord_cancellable, + colord_client_device_get_profile_for_qualifiers_cb, + printer); + + /* save for the future */ + g_free (printer->colord_qualifier); + printer->colord_qualifier = g_strdup (qualifier); + + /* update the UI */ + colord_update_ui_from_settings (printer); +out: + g_free (qualifier); + g_strfreev (qualifiers); +} + +static void +colord_client_device_connect_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data); + gboolean ret; + GError *error = NULL; + + /* get details about the device */ + ret = cd_device_connect_finish (CD_DEVICE (source_object), res, &error); + if (!ret) + { + g_warning ("failed to get properties from the colord device: %s", + error->message); + g_error_free (error); + goto out; + } +out: + /* update the UI */ + colord_update_ui_from_settings (printer); +} + +static void +colord_client_find_device_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data); + GError *error = NULL; + + /* get the new device */ + printer->colord_device = cd_client_find_device_finish (printer->colord_client, + res, + &error); + if (printer->colord_device == NULL) + { + g_warning ("failed to get find a colord device: %s", + error->message); + g_error_free (error); + goto out; + } + + /* get details about the device */ + g_cancellable_reset (printer->colord_cancellable); + cd_device_connect (printer->colord_device, + printer->colord_cancellable, + colord_client_device_connect_cb, + printer); +out: + /* update the UI */ + colord_update_ui_from_settings (printer); +} + +static void +colord_update_device (GtkPrinterCups *printer) +{ + gchar *colord_device_id = NULL; + + /* not yet connected to the daemon */ + if (!cd_client_get_connected (printer->colord_client)) + goto out; + + /* not yet assigned a printer */ + if (printer->ppd_file == NULL) + goto out; + + /* old cached profile no longer valid */ + if (printer->colord_profile) + { + g_object_unref (printer->colord_profile); + printer->colord_profile = NULL; + } + + /* old cached device no longer valid */ + if (printer->colord_device) + { + g_object_unref (printer->colord_device); + printer->colord_device = NULL; + } + + /* generate a known ID */ + colord_device_id = g_strdup_printf ("cups-%s", gtk_printer_get_name (GTK_PRINTER (printer))); + + g_cancellable_reset (printer->colord_cancellable); + cd_client_find_device (printer->colord_client, + colord_device_id, + printer->colord_cancellable, + colord_client_find_device_cb, + printer); +out: + g_free (colord_device_id); + + /* update the UI */ + colord_update_ui_from_settings (printer); +} + +static void +colord_client_connect_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean ret; + GError *error = NULL; + GtkPrinterCups *printer = GTK_PRINTER_CUPS (user_data); + + ret = cd_client_connect_finish (CD_CLIENT (source_object), + res, &error); + if (!ret) + { + g_warning ("failed to contact colord: %s", error->message); + g_error_free (error); + } + + /* refresh the device */ + colord_update_device (printer); +} +#endif + /** * gtk_printer_cups_new: * @@ -124,10 +505,12 @@ gtk_printer_cups_finalize (GObject *object) **/ GtkPrinterCups * gtk_printer_cups_new (const char *name, - GtkPrintBackend *backend) + GtkPrintBackend *backend, + gpointer colord_client) { GObject *result; gboolean accepts_pdf; + GtkPrinterCups *printer; #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1 accepts_pdf = TRUE; @@ -141,8 +524,21 @@ gtk_printer_cups_new (const char *name, "is-virtual", FALSE, "accepts-pdf", accepts_pdf, NULL); + printer = GTK_PRINTER_CUPS (result); - return (GtkPrinterCups *) result; +#ifdef HAVE_COLORD + /* connect to colord */ + if (colord_client != NULL) + { + printer->colord_cancellable = g_cancellable_new (); + printer->colord_client = g_object_ref (CD_CLIENT (colord_client)); + cd_client_connect (printer->colord_client, + printer->colord_cancellable, + colord_client_connect_cb, + printer); + } +#endif + return printer; } ppd_file_t * diff --git a/modules/printbackends/cups/gtkprintercups.h b/modules/printbackends/cups/gtkprintercups.h index 6868232f29..e29b1b9739 100644 --- a/modules/printbackends/cups/gtkprintercups.h +++ b/modules/printbackends/cups/gtkprintercups.h @@ -26,6 +26,11 @@ #include "gtkcupsutils.h" #include +#include + +#ifdef HAVE_COLORD +#include +#endif G_BEGIN_DECLS @@ -62,6 +67,14 @@ struct _GtkPrinterCups guint get_remote_ppd_poll; gint get_remote_ppd_attempts; GtkCupsConnectionTest *remote_cups_connection_test; +#ifdef HAVE_COLORD + CdClient *colord_client; + CdDevice *colord_device; + CdProfile *colord_profile; + GCancellable *colord_cancellable; + gchar *colord_title; + gchar *colord_qualifier; +#endif }; struct _GtkPrinterCupsClass @@ -72,11 +85,19 @@ struct _GtkPrinterCupsClass GType gtk_printer_cups_get_type (void) G_GNUC_CONST; void gtk_printer_cups_register_type (GTypeModule *module); + GtkPrinterCups *gtk_printer_cups_new (const char *name, - GtkPrintBackend *backend); + GtkPrintBackend *backend, + gpointer colord_client); ppd_file_t *gtk_printer_cups_get_ppd (GtkPrinterCups *printer); const gchar *gtk_printer_cups_get_ppd_name (GtkPrinterCups *printer); +#ifdef HAVE_COLORD +void gtk_printer_cups_update_settings (GtkPrinterCups *printer, + GtkPrintSettings *settings, + GtkPrinterOptionSet *set); +#endif + G_END_DECLS #endif /* __GTK_PRINTER_CUPS_H__ */