From db29c24e3ff75938775aa1f4072e346aeb7f6a9c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 1 Mar 2011 16:05:48 +0000 Subject: [PATCH] Add colord support to CUPS which allows Linux printers to be color managed This functionality is possible because of lots of help from Tim Waugh -- thanks! --- scheduler/Makefile | 1 + scheduler/colord.c | 784 ++++++++++++++++++++++++++++++++++++++++++++++++++ scheduler/colord.h | 41 +++ scheduler/ipp.c | 18 +- scheduler/printers.c | 69 +++++ scheduler/printers.h | 4 + 6 files changed, 914 insertions(+), 3 deletions(-) create mode 100644 scheduler/colord.c create mode 100644 scheduler/colord.h diff --git a/scheduler/Makefile b/scheduler/Makefile index 3c7da8e..b9c47d3 100644 --- a/scheduler/Makefile +++ b/scheduler/Makefile @@ -27,6 +27,7 @@ CUPSDOBJS = \ file.o \ main.o \ ipp.o \ + colord.o \ listen.o \ job.o \ log.o \ diff --git a/scheduler/colord.c b/scheduler/colord.c new file mode 100644 index 0000000..bd06e1c --- /dev/null +++ b/scheduler/colord.c @@ -0,0 +1,784 @@ +/* + * "$Id$" + * + * colord integration for the CUPS scheduler. + * + * Copyright 2011 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contents: + * + * colordRegisterPrinter() - Register profiles for a printer. + * colordUnregisterPrinter() - Unregister profiles for a printer. + * colordStart() - Get a connection to the system bus. + * colordStop() - Release any connection to the system bus + * so that added profiles and devices are + * automatically removed. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + +#ifdef HAVE_DBUS + +#include +#include + +/* + * Defines used by colord. See the reference docs for further details: + * http://colord.hughsie.com/api/ref-dbus.html + */ +#define COLORD_SCOPE_NORMAL "normal" /* System scope */ +#define COLORD_SCOPE_TEMP "temp" /* Process scope */ +#define COLORD_SCOPE_DISK "disk" /* Lives forever, as stored in DB */ + +#define COLORD_RELATION_SOFT "soft" /* Mapping is not default */ +#define COLORD_RELATION_HARD "hard" /* Explicitly mapped profile */ + +#define COLORD_SPACE_RGB "rgb" /* RGB colorspace */ +#define COLORD_SPACE_CMYK "cmyk" /* CMYK colorspace */ +#define COLORD_SPACE_GRAY "gray" /* Gray colorspace */ +#define COLORD_SPACE_UNKNOWN "unknown" /* Unknown colorspace */ + +#define COLORD_MODE_PHYSICAL "physical" /* Actual device */ +#define COLORD_MODE_VIRTUAL "virtual" /* Virtual device with no hardware */ + +#define COLORD_KIND_PRINTER "printer" /* printing output device */ + +/* the timeout for connecting to colord */ +#define COLORD_DBUS_TIMEOUT 5000 /* ms */ + +/* This is static */ +static DBusConnection *con = NULL; + +/* + * 'colordStart()' - Get a connection to the system bus. + */ + +void +colordStart(void) +{ + if (con) + return; + con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL); +} + +/* + * 'colordStop()' - Release any connection to the system bus so that + * added profiles and devices are automatically removed. + */ + +void +colordStop(void) +{ + if (con == NULL) + return; + dbus_connection_unref(con); + con = NULL; +} + +/* + * 'message_dict_add_strings()' - add two strings to a dictionary. + */ + +static void +message_dict_add_strings (DBusMessageIter *dict, + const char *key, + const char *value) +{ + DBusMessageIter entry; + dbus_message_iter_open_container(dict, + DBUS_TYPE_DICT_ENTRY, + NULL, + &entry); + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value); + dbus_message_iter_close_container(dict, &entry); +} + +/* + * 'colordCreateProfile()' - Create a color profile for a printer. + * + * Notes: When creating the device, we can create + */ + +static void +colordCreateProfile (cups_array_t *profiles, /* I - Profiles array */ + const char *printer_name, /* I - Printer name */ + const char *qualifier, /* I - Profile qualifier */ + const char *colorspace, /* I - Profile colorspace */ + const char **format, /* I - Profile qualifier format */ + const char *iccfile, /* I - ICC filename */ + const char *scope) /* I - The scope of the profile, e.g. + 'normal', 'temp' or 'disk' */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusMessageIter dict; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + char *idstr; /* Profile ID string */ + size_t idstrlen; /* Profile ID allocated length */ + const char *profile_path; /* Device object path */ + char format_str[1024]; /* Qualifier format as a string */ + + /* + * Create the profile... + */ + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + "/org/freedesktop/ColorManager", + "org.freedesktop.ColorManager", + "CreateProfile"); + + /* create a profile id */ + idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1; + idstr = malloc (idstrlen); + if (!idstr) + goto out; + snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile id of %s", + idstr); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope); + + /* mush the qualifier format into a simple string */ + snprintf(format_str, sizeof(format_str), "%s.%s.%s", + format[0], + format[1], + format[2]); + + /* set initial properties */ + dbus_message_iter_open_container(&args, + DBUS_TYPE_ARRAY, + "{ss}", + &dict); + message_dict_add_strings(&dict, "Qualifier", qualifier); + message_dict_add_strings(&dict, "Format", format_str); + message_dict_add_strings(&dict, "Colorspace", colorspace); + if (iccfile != NULL) + message_dict_add_strings(&dict, "Filename", iccfile); + dbus_message_iter_close_container(&args, &dict); + + /* send syncronous */ + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)", + idstr, scope); + reply = dbus_connection_send_with_reply_and_block(con, + message, + COLORD_DBUS_TIMEOUT, + &error); + if (reply == NULL) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "failed to CreateProfile: %s:%s", + error.name, error.message); + dbus_error_free(&error); + goto out; + } + + /* get reply data */ + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "incorrect reply type"); + goto out; + } + dbus_message_iter_get_basic(&args, &profile_path); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "created profile %s", + profile_path); + cupsArrayAdd(profiles, strdup(profile_path)); + +out: + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); + free (idstr); +} + +/* + * 'colordDeviceAddProfile()' - Assign a profile to a device. + */ + +static void +colordDeviceAddProfile (const char *device_path, /* I - Device object path */ + const char *profile_path, /* I - Profile object path */ + const char *relation) /* I - Device relation, either 'soft' or 'hard' */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + device_path, + "org.freedesktop.ColorManager.Device", + "AddProfile"); + + /* send profile path as the argument */ + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation); + dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Calling %s:AddProfile(%s) [%s]", + device_path, profile_path, relation); + + /* send syncronous */ + dbus_error_init(&error); + reply = dbus_connection_send_with_reply_and_block(con, + message, + COLORD_DBUS_TIMEOUT, + &error); + if (reply == NULL) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "failed to AddProfile: %s:%s", + error.name, error.message); + dbus_error_free(&error); + goto out; + } +out: + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); +} + +/* + * 'colordCreateDevice()' - Create a device and register profiles. + */ + +static void +colordCreateDevice (cupsd_printer_t *p, /* I - Printer */ + ppd_file_t *ppd, /* I - PPD file */ + cups_array_t *profiles, /* I - Profiles array */ + const char *colorspace, /* I - Device colorspace, e.g. 'rgb' */ + char **format, /* I - Device qualifier format */ + const char *relation, /* I - Profile relation, either 'soft' or 'hard' */ + const char *scope) /* I - The scope of the device, e.g. + 'normal', 'temp' or 'disk' */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusMessageIter dict; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + const char *device_path; /* Device object path */ + const char *profile_path; /* Profile path */ + char *default_profile_path = NULL; + /* Default profile path */ + char device_id[1024]; /* Device ID as understood by colord */ + char format_str[1024]; /* Qualifier format as a string */ + + /* + * Create the device... + */ + + snprintf(device_id, sizeof(device_id), "cups-%s", p->name); + device_path = device_id; + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + "/org/freedesktop/ColorManager", + "org.freedesktop.ColorManager", + "CreateDevice"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope); + + /* mush the qualifier format into a simple string */ + snprintf(format_str, sizeof(format_str), "%s.%s.%s", + format[0], + format[1], + format[2]); + + /* set initial properties */ + dbus_message_iter_open_container(&args, + DBUS_TYPE_ARRAY, + "{ss}", + &dict); + message_dict_add_strings(&dict, "Colorspace", colorspace); + message_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL); + if (ppd->manufacturer != NULL) + message_dict_add_strings(&dict, "Vendor", ppd->manufacturer); + if (ppd->modelname != NULL) + message_dict_add_strings(&dict, "Model", ppd->modelname); + if (p->sanitized_device_uri != NULL) + message_dict_add_strings(&dict, "Serial", p->sanitized_device_uri); + message_dict_add_strings(&dict, "Format", format_str); + message_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER); + dbus_message_iter_close_container(&args, &dict); + + /* send syncronous */ + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)", + device_id, scope); + reply = dbus_connection_send_with_reply_and_block(con, + message, + COLORD_DBUS_TIMEOUT, + &error); + if (reply == NULL) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "failed to CreateDevice: %s:%s", + error.name, error.message); + dbus_error_free(&error); + goto out; + } + + /* get reply data */ + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "incorrect reply type"); + goto out; + } + dbus_message_iter_get_basic(&args, &device_path); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "created device %s", + device_path); + + /* add profiles */ + for (profile_path = cupsArrayFirst(profiles); + profile_path; + profile_path = cupsArrayNext(profiles)) + { + colordDeviceAddProfile (device_path, profile_path, relation); + } + +out: + free(default_profile_path); + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); +} + +/* + * 'colordFindDeviceById()' - Finds a device + */ + +static char * +colordFindDeviceById (const char *device_id) /* I - Device ID string */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + const char *device_path_tmp; /* Device object path */ + char *device_path = NULL; /* Device object path */ + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + "/org/freedesktop/ColorManager", + "org.freedesktop.ColorManager", + "FindDeviceById"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id); + + /* send syncronous */ + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById(%s)", device_id); + reply = dbus_connection_send_with_reply_and_block(con, + message, + COLORD_DBUS_TIMEOUT, + &error); + if (reply == NULL) + { + /* this can happen normally on start-up */ + cupsdLogMessage(CUPSD_LOG_DEBUG, + "failed to DeleteDevice: %s:%s", + error.name, error.message); + dbus_error_free(&error); + goto out; + } + + /* get reply data */ + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "incorrect reply type"); + goto out; + } + dbus_message_iter_get_basic(&args, &device_path_tmp); + if (device_path_tmp != NULL) + device_path = strdup (device_path_tmp); +out: + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); + return device_path; +} + +/* + * 'colordDeleteDevice()' - Delete a device + */ + +static void +colordDeleteDevice (const char *device_id) /* I - Device ID string */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + char *device_path; /* Device object path */ + + /* + * Find the device... + */ + + device_path = colordFindDeviceById (device_id); + if (device_path == NULL) + { + /* this can happen normally on start-up */ + cupsdLogMessage(CUPSD_LOG_WARN, + "failed to find device: %s", + device_id); + goto out; + } + + /* + * Delete the device... + */ + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + "/org/freedesktop/ColorManager", + "org.freedesktop.ColorManager", + "DeleteDevice"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id); + + /* send syncronous */ + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id); + reply = dbus_connection_send_with_reply_and_block(con, + message, + COLORD_DBUS_TIMEOUT, + &error); + if (reply == NULL) + { + /* this can happen normally on start-up */ + cupsdLogMessage(CUPSD_LOG_DEBUG, + "failed to DeleteDevice: %s:%s", + error.name, error.message); + dbus_error_free(&error); + goto out; + } +out: + free (device_path); + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); +} + +/* + * 'colordGetQualifierFormat()' - Get the qualifier format. + * + * Notes: Returns a value of "ColorSpace.MediaType.Resolution" by default + */ + +char ** +colordGetQualifierFormat(ppd_file_t *ppd) +{ + char **format; /* Qualifier format tuple */ + const char *tmp; /* Temporary string */ + ppd_attr_t *attr; /* Profile attributes */ + + /* create 3-tuple */ + format = calloc(3, sizeof(char*)); + + /* get 1st section */ + tmp = "cupsICCQualifier1"; + attr = ppdFindAttr(ppd, tmp, NULL); + if (attr != NULL) + tmp = attr->value; + else + { + tmp = "DefaultColorSpace"; + attr = ppdFindAttr(ppd, tmp, NULL); + } + if (attr == NULL) + { + tmp = "DefaultColorModel"; + attr = ppdFindAttr(ppd, tmp, NULL); + } + if (attr == NULL) + { + tmp = ""; + } + if (strncmp(tmp, "Default", 7) == 0) + tmp += 7; + format[0] = strdup(tmp); + + /* get 2nd section */ + tmp = "cupsICCQualifier2"; + attr = ppdFindAttr(ppd, tmp, NULL); + if (attr != NULL) + tmp = attr->value; + else + { + tmp = "DefaultMediaType"; + attr = ppdFindAttr(ppd, tmp, NULL); + } + if (attr == NULL) + { + tmp = ""; + } + if (strncmp(tmp, "Default", 7) == 0) + tmp += 7; + format[1] = strdup(tmp); + + /* get 3rd section */ + tmp = "cupsICCQualifier3"; + attr = ppdFindAttr(ppd, tmp, NULL); + if (attr != NULL) + tmp = attr->value; + else + { + tmp = "DefaultResolution"; + attr = ppdFindAttr(ppd, tmp, NULL); + } + if (attr == NULL) + { + tmp = ""; + } + if (strncmp(tmp, "Default", 7) == 0) + tmp += 7; + format[2] = strdup(tmp); + + return format; +} + +/* + * 'colordRegisterPrinter()' - Register profiles for a printer. + */ + +void +colordRegisterPrinter(cupsd_printer_t *p) /* I - printer */ +{ + char ppdfile[1024], /* PPD filename */ + iccfile[1024]; /* ICC filename */ + ppd_file_t *ppd; /* PPD file */ + cups_array_t *profiles; /* Profile paths array */ + const char *profile_key; /* Profile keyword */ + ppd_attr_t *attr; /* Profile attributes */ + const char *device_colorspace; /* Device colorspace */ + char **format; /* Qualifier format tuple */ + int i; /* Loop counter */ + + /* + * Do nothing for discovered printers as they will have local color + * correction + */ + + if (p->type & CUPS_PRINTER_DISCOVERED) + return; + + /* + * Ensure we have a DBus connection + */ + + colordStart(); + if (con == NULL) + return; + + /* + * Try opening the PPD file for this printer... + */ + + snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); + if ((ppd = ppdOpenFile(ppdfile)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cannot open %s", + ppdfile); + return; + } + + /* + * Find out the qualifier format + */ + + format = colordGetQualifierFormat(ppd); + + /* + * See if we have any embedded profiles... + */ + + profiles = cupsArrayNew3 (NULL, NULL, NULL, 0, NULL, + (cups_afree_func_t) free); + profile_key = "cupsICCProfile"; + attr = ppdFindAttr(ppd, profile_key, NULL); + for (; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL)) + if (attr->spec[0] && attr->value && attr->value[0]) + { + if (attr->value[0] != '/') + snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, + attr->value); + else + strlcpy(iccfile, attr->value, sizeof(iccfile)); + + if (access(iccfile, 0)) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "no access to %s", + iccfile); + continue; + } + + colordCreateProfile(profiles, + p->name, + attr->spec, + COLORD_SPACE_UNKNOWN, + (const char **)format, + iccfile, + COLORD_SCOPE_TEMP); + } + + /* + * Add the grayscale profile first. We always have a grayscale profile. + */ + + colordCreateProfile(profiles, + p->name, + "Gray..", + COLORD_SPACE_GRAY, + (const char **)format, + NULL, + COLORD_SCOPE_TEMP); + + /* + * Then add the RGB/CMYK/DeviceN color profile... + */ + + device_colorspace = "unknown"; + switch (ppd->colorspace) + { + case PPD_CS_RGB : + case PPD_CS_CMY : + device_colorspace = COLORD_SPACE_RGB; + colordCreateProfile(profiles, + p->name, + "RGB..", + COLORD_SPACE_RGB, + (const char **)format, + NULL, + COLORD_SCOPE_TEMP); + break; + case PPD_CS_RGBK : + case PPD_CS_CMYK : + device_colorspace = COLORD_SPACE_CMYK; + colordCreateProfile(profiles, + p->name, + "CMYK..", + COLORD_SPACE_CMYK, + (const char **)format, + NULL, + COLORD_SCOPE_TEMP); + break; + case PPD_CS_GRAY : + device_colorspace = COLORD_SPACE_GRAY; + break; + case PPD_CS_N : + colordCreateProfile(profiles, + p->name, + "DeviceN..", + COLORD_SPACE_UNKNOWN, + (const char **)format, + NULL, + COLORD_SCOPE_TEMP); + break; + } + + /* + * Register the device with colord. + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"", + p->name); + colordCreateDevice (p, + ppd, + profiles, + device_colorspace, + format, + COLORD_RELATION_SOFT, + COLORD_SCOPE_TEMP); + + /* + * Free any memory we used... + */ + + cupsArrayDelete(profiles); + for (i=0; i<3; i++) + free(format[i]); + free(format); + + ppdClose(ppd); +} + +/* + * 'colordUnregisterPrinter()' - Unregister profiles for a printer. + */ + +void +colordUnregisterPrinter(cupsd_printer_t *p) /* I - printer */ +{ + char device_id[1024]; /* Device ID as understood by colord */ + + /* + * Ensure we have a DBus connection + */ + + colordStart(); + if (con == NULL) + return; + + /* + * Just delete the device itself, and leave the profiles registered + */ + + snprintf(device_id, sizeof(device_id), "cups-%s", p->name); + colordDeleteDevice(device_id); +} + +#endif /* HAVE_DBUS */ + +/* + * End of "$Id$". + */ diff --git a/scheduler/colord.h b/scheduler/colord.h new file mode 100644 index 0000000..75bdd3b --- /dev/null +++ b/scheduler/colord.h @@ -0,0 +1,41 @@ +/* + * "$Id$" + * + * colord integration for the CUPS scheduler. + * + * Copyright 2011 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +void colordRegisterPrinter(cupsd_printer_t *p); +void colordUnregisterPrinter(cupsd_printer_t *p); +void colordStart(void); +void colordStop(void); + +/* + * End of "$Id$". + */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c index b9903d1..b5af36f 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -2921,17 +2921,23 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ cupsdSetPrinterReasons(printer, "none"); -#ifdef __APPLE__ /* * (Re)register color profiles... */ if (!RunUser) { + cupsdCmsRegisterPrinter(printer); +#ifdef __APPLE__ + /* + * FIXME: ideally the ColorSync stuff would be moved to colorsync.c + * and the colorsyncRegisterProfiles() would be called from + * cupsdCmsRegisterPrinter() in printers.c + */ apple_unregister_profiles(printer); apple_register_profiles(printer); - } #endif /* __APPLE__ */ + } } /* @@ -7028,11 +7034,17 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name); unlink(filename); -#ifdef __APPLE__ /* * Unregister color profiles... */ + cupsdCmsUnregisterPrinter(printer); +#ifdef __APPLE__ + /* + * FIXME: ideally the ColorSync stuff would be moved to colorsync.c + * and the colorsyncUnregisterPrinter() would be called from + * cupsdCmsUnregisterPrinter() in printers.c + */ apple_unregister_profiles(printer); #endif /* __APPLE__ */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 6920801..e830499 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -80,6 +80,9 @@ # include #endif /* __APPLE__ */ +#ifdef HAVE_DBUS +# include "colord.h" +#endif /* HAVE_DBUS */ /* * Local functions... @@ -712,6 +715,53 @@ cupsdDeleteAllPrinters(void) } } +/* + * 'cupsdCmsRegisterPrinter()' - Registers a printer and profiles with the CMS + */ + +void +cupsdCmsRegisterPrinter(cupsd_printer_t *p) +{ +#if defined(HAVE_DBUS) + colordRegisterPrinter(p); +#endif /* defined(HAVE_DBUS) */ +} + +/* + * 'cupsdCmsUnregisterPrinter()' - Unregisters a printer and profiles with the CMS + */ + +void +cupsdCmsUnregisterPrinter(cupsd_printer_t *p) +{ +#if defined(HAVE_DBUS) + colordUnregisterPrinter(p); +#endif /* defined(HAVE_DBUS) */ +} + +/* + * 'cupsdCmsStart()' - Starts the CMS + */ + +void +cupsdCmsStart(void) +{ +#if defined(HAVE_DBUS) + colordStart(); +#endif /* defined(HAVE_DBUS) */ +} + +/* + * 'cupsdCmsStop()' - Stops the CMS + */ + +void +cupsdCmsStop(void) +{ +#if defined(HAVE_DBUS) + colordStop(); +#endif /* defined(HAVE_DBUS) */ +} /* * 'cupsdDeletePrinter()' - Delete a printer from the system. @@ -752,6 +802,12 @@ cupsdDeletePrinter( "Job stopped."); /* + * Unregister profiles... + */ + + cupsdCmsUnregisterPrinter(p); + + /* * If this printer is the next for browsing, point to the next one... */ @@ -1418,6 +1474,12 @@ cupsdRenamePrinter( } /* + * Unregister profiles... + */ + + cupsdCmsUnregisterPrinter(p); + + /* * Rename the printer... */ @@ -2644,6 +2706,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ #endif /* __sgi */ /* + * Re-register profiles... + */ + + cupsdCmsUnregisterPrinter(p); + cupsdCmsRegisterPrinter(p); + + /* * Let the browse protocols reflect the change */ diff --git a/scheduler/printers.h b/scheduler/printers.h index 1751578..3820428 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -170,6 +170,10 @@ extern const char *cupsdValidateDest(const char *uri, cups_ptype_t *dtype, cupsd_printer_t **printer); extern void cupsdWritePrintcap(void); +extern void cupsdCmsRegisterPrinter(cupsd_printer_t *p); +extern void cupsdCmsUnregisterPrinter(cupsd_printer_t *p); +extern void cupsdCmsStart(void); +extern void cupsdCmsStop(void); /* -- 1.7.6.2