diff options
author | Richard Hughes <richard@hughsie.com> | 2013-04-30 11:30:26 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2013-05-17 09:39:51 +0100 |
commit | 9b955ffc30af9fc68a4e38a5486f996ada08e074 (patch) | |
tree | f4b6deb226dd42edb6692623008d567f490fc8ec | |
parent | 561dfd01059112539d1afcedc1de64595472ee43 (diff) | |
download | colord-9b955ffc30af9fc68a4e38a5486f996ada08e074.tar.gz |
Add a shim libcolordcompat library with some helpers for ArgyllCMS
ArgyllCMS uses WCS for Windows and ColorSync for OS-X to store the device to
profile mapping data. For situations where these are not available it also
provides the the UCMM functionality that stores the mapping as JSON data.
Providing a simple shim library allows ArgyllCMS to simply dlopen() the
/usr/lib64/libcolordcompat.so file if it exists and use colord for the mapping
data on Linux platforms.
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | contrib/colord.spec.in | 3 | ||||
-rw-r--r-- | lib/Makefile.am | 5 | ||||
-rw-r--r-- | lib/compat/Makefile.am | 42 | ||||
-rw-r--r-- | lib/compat/cd-edid.c | 389 | ||||
-rw-r--r-- | lib/compat/cd-edid.h | 84 | ||||
-rw-r--r-- | lib/compat/test.c | 58 |
8 files changed, 592 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 205f46f..0566755 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,6 +35,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ --enable-fd-fallback \ --enable-gtk \ --enable-sane \ + --enable-libcolordcompat \ --disable-print-profiles \ --disable-bash-completion \ --enable-gtk-doc \ diff --git a/configure.ac b/configure.ac index bd1f424..4fb1770 100644 --- a/configure.ac +++ b/configure.ac @@ -212,7 +212,14 @@ if test "x$with_systemdsystemunitdir" != "xno"; then fi AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$systemdsystemunitdir"]) - +dnl **** Check if we should build libcolordcompat **** +AC_ARG_ENABLE(libcolordcompat, AS_HELP_STRING([--enable-libcolordcompat], + [Enable libcolordcompat.so which is used by ArgyllCMS]), + build_libcolordcompat=$enableval, build_libcolordcompat=no) +if test x$build_libcolordcompat != xno; then + AC_DEFINE(BUILD_LIBCOLORDCOMPAT,1,[Build libcolordcompat.so]) +fi +AM_CONDITIONAL(BUILD_LIBCOLORDCOMPAT, test x$build_libcolordcompat = xyes) dnl --------------------------------------------------------------------------- dnl - Use libsystemd-login to track the process seat @@ -402,6 +409,7 @@ lib/colord/Makefile lib/colorhug/Makefile lib/colorhug/colorhug.pc lib/colorhug/ch-version.h +lib/compat/Makefile lib/dtp94/Makefile lib/huey/Makefile lib/munki/Makefile @@ -428,6 +436,7 @@ echo " GUdev support: ${enable_gudev} GUsb support: ${enable_gusb} Extra print profiles: ${enable_print_profiles} + Building libcolordcompat: ${build_libcolordcompat} Vala API generator: ${has_vapigen} Daemon user: ${daemon_user} udev rules.d dir: ${with_udevrulesdir} diff --git a/contrib/colord.spec.in b/contrib/colord.spec.in index fd59b0d..0bd46cb 100644 --- a/contrib/colord.spec.in +++ b/contrib/colord.spec.in @@ -125,6 +125,9 @@ ulimit -Sv 2000000 %if 0%{?enable_sane} --enable-sane \ %endif +%if !0%{?rhel} + --enable-libcolordcompat \ +%endif --disable-static \ --disable-rpath \ --disable-examples \ diff --git a/lib/Makefile.am b/lib/Makefile.am index 6f6567a..e5c4e61 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,11 @@ SUBDIRS = \ colord +if BUILD_LIBCOLORDCOMPAT +SUBDIRS += \ + compat +endif + if HAVE_GUSB SUBDIRS += \ colorhug \ diff --git a/lib/compat/Makefile.am b/lib/compat/Makefile.am new file mode 100644 index 0000000..bc10445 --- /dev/null +++ b/lib/compat/Makefile.am @@ -0,0 +1,42 @@ +AM_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/colord \ + -I$(top_builddir)/lib \ + -I. \ + -DCD_COMPILATION \ + -DG_LOG_DOMAIN=\"Cd\" + +COLORD_LIBS = \ + $(top_builddir)/lib/colord/libcolord.la + +lib_LTLIBRARIES = \ + libcolordcompat.la + +libcolordcompat_includedir = $(includedir)/colord-1/colord +libcolordcompat_include_HEADERS = \ + cd-edid.h + +libcolordcompat_la_SOURCES = \ + cd-edid.c \ + cd-edid.h + +libcolordcompat_la_LIBADD = \ + $(GLIB_LIBS) \ + $(COLORD_LIBS) + +libcolordcompat_la_LDFLAGS = \ + -avoid-version \ + -export-dynamic \ + -no-undefined \ + -export-symbols-regex '^cd_.*' + +libcolordcompat_la_CFLAGS = \ + $(WARNINGFLAGS_C) + +clean-local: + rm -f *~ + rm -f $(CLEANFILES) + +-include $(top_srcdir)/git.mk diff --git a/lib/compat/cd-edid.c b/lib/compat/cd-edid.c new file mode 100644 index 0000000..6df8d5f --- /dev/null +++ b/lib/compat/cd-edid.c @@ -0,0 +1,389 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2013 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:cd-edid + * @short_description: Compatibility routines for applications that process the EDID + * + * These functions here are designed as a ucmm-like wrapper for ArgyllCMS. + * Other software should use the native functionality in libcolord rather than + * this shim functionality. + */ + +#include "config.h" + +#include <colord.h> +#include <string.h> + +#include "cd-edid.h" + +/** + * cd_edid_install_profile: + * @scope: where to install the profile, e.g. %CD_EDID_SCOPE_USER + * @edid: the EDID data, typically just 128 bytes in size + * @edid_len: the size in bytes of @edid_len + * @profile_fn: the profile filename to install + * + * Install a profile for a given monitor. + * + * Return value: a %CdEdidError, e.g. %CD_EDID_ERROR_OK + * + * Since: 0.1.34 + **/ +CdEdidError +cd_edid_install_profile (unsigned char *edid, + int edid_len, + CdEdidScope scope, + char *profile_fn) +{ + CdClient *client = NULL; + CdDevice *device = NULL; + CdEdidError rc = CD_EDID_ERROR_OK; + CdProfile *profile = NULL; + gboolean ret; + gchar *md5 = NULL; + GError *error = NULL; + GFile *file; + + g_return_val_if_fail (profile_fn != NULL, CD_EDID_ERROR_RESOURCE); + + /* bad input */ + if (edid == NULL || edid_len == 0) { + rc = CD_EDID_ERROR_NO_DATA; + goto out; + } + + /* conect to daemon */ + client = cd_client_new (); + ret = cd_client_connect_sync (client, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("Failed to connect to colord: %s", error->message); + g_error_free (error); + goto out; + } + + /* find device that matches the output EDID */ + md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, + (const gchar *)edid, + (gssize) edid_len); + device = cd_client_find_device_by_property_sync (client, + CD_DEVICE_METADATA_OUTPUT_EDID_MD5, + md5, + NULL, + &error); + if (device == NULL) { + rc = CD_EDID_ERROR_MONITOR_NOT_FOUND; + g_warning ("Failed to find device that matches %s: %s", + md5, error->message); + g_error_free (error); + goto out; + } + + /* read device properties */ + ret = cd_device_connect_sync (device, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("device disappeared: %s", error->message); + g_error_free (error); + goto out; + } + + /* import profile */ + file = g_file_new_for_path (profile_fn); + profile = cd_client_import_profile_sync (client, file, NULL, &error); + if (profile == NULL) { + rc = CD_EDID_ERROR_NO_PROFILE; + g_warning ("Could not import profile %s: %s", + profile_fn, + error->message); + g_error_free (error); + goto out; + } + + /* add profile to device */ + ret = cd_device_add_profile_sync (device, + CD_DEVICE_RELATION_HARD, + profile, + NULL, + &error); + if (!ret) { + rc = CD_EDID_ERROR_SET_CONFIG; + g_warning ("could not add profile %s to device %s: %s", + cd_profile_get_id (profile), + cd_device_get_id (device), + error->message); + g_error_free (error); + goto out; + } + + /* install system-wide */ + if (scope == CD_EDID_SCOPE_SYSTEM) { + ret = cd_profile_install_system_wide_sync (profile, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_PROFILE_COPY; + g_warning ("could not set profile %s systemwide: %s", + cd_profile_get_id (profile), + error->message); + g_error_free (error); + goto out; + } + } +out: + if (client != NULL) + g_object_unref (client); + if (device != NULL) + g_object_unref (device); + if (profile != NULL) + g_object_unref (profile); + g_free (md5); + return rc; +} + +/** + * cd_edid_remove_profile: + * @edid: the EDID data, typically just 128 bytes in size + * @edid_len: the size in bytes of @edid_len + * @profile_fn: the profile filename to remove + * + * Un-install a profile for a given monitor. + * + * Return value: a %CdEdidError, e.g. %CD_EDID_ERROR_OK + * + * Since: 0.1.34 + **/ +CdEdidError +cd_edid_remove_profile (unsigned char *edid, + int edid_len, + char *profile_fn) +{ + CdClient *client = NULL; + CdDevice *device = NULL; + CdProfile *profile = NULL; + gboolean ret; + gchar *md5 = NULL; + GError *error = NULL; + GFile *file = NULL; + CdEdidError rc = CD_EDID_ERROR_OK; + + g_return_val_if_fail (profile_fn != NULL, CD_EDID_ERROR_RESOURCE); + + /* bad input */ + if (edid == NULL || edid_len == 0) { + rc = CD_EDID_ERROR_NO_DATA; + goto out; + } + + /* conect to daemon */ + client = cd_client_new (); + ret = cd_client_connect_sync (client, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("Failed to connect to colord: %s", error->message); + g_error_free (error); + goto out; + } + + /* find device that matches the output EDID */ + md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, + (const gchar *)edid, + (gssize) edid_len); + device = cd_client_find_device_by_property_sync (client, + CD_DEVICE_METADATA_OUTPUT_EDID_MD5, + md5, + NULL, + &error); + if (device == NULL) { + rc = CD_EDID_ERROR_MONITOR_NOT_FOUND; + g_warning ("Failed to find device that matches %s: %s", + md5, error->message); + g_error_free (error); + goto out; + } + + /* read device properties */ + ret = cd_device_connect_sync (device, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("device disappeared: %s", error->message); + g_error_free (error); + goto out; + } + + /* find profile */ + file = g_file_new_for_path (profile_fn); + profile = cd_client_find_profile_by_filename_sync (client, + profile_fn, + NULL, + &error); + if (profile == NULL) { + rc = CD_EDID_ERROR_NO_PROFILE; + g_warning ("Could not find profile %s: %s", + profile_fn, + error->message); + g_error_free (error); + goto out; + } + + /* read profile properties */ + ret = cd_profile_connect_sync (profile, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("profile disappeared: %s", error->message); + g_error_free (error); + goto out; + } + + /* remove profile from device */ + ret = cd_device_remove_profile_sync (device, + profile, + NULL, + &error); + if (!ret) { + rc = CD_EDID_ERROR_SET_CONFIG; + g_warning ("could not remove profile %s from device %s: %s", + cd_profile_get_id (profile), + cd_device_get_id (device), + error->message); + g_error_free (error); + goto out; + } +out: + if (file != NULL) + g_object_unref (file); + if (client != NULL) + g_object_unref (client); + if (device != NULL) + g_object_unref (device); + if (profile != NULL) + g_object_unref (profile); + g_free (md5); + return rc; +} + +/** + * cd_edid_get_profile: + * @edid: the EDID data, typically just 128 bytes in size + * @edid_len: the size in bytes of @edid_len + * @profile_fn: the returned profile filename, use free() when done + * + * Get an associated monitor profile. + * + * Return value: a %CdEdidError, e.g. %CD_EDID_ERROR_OK + * + * Since: 0.1.34 + **/ +CdEdidError +cd_edid_get_profile (unsigned char *edid, + int edid_len, + char **profile_fn) +{ + CdClient *client = NULL; + CdDevice *device = NULL; + CdProfile *profile = NULL; + const gchar *filename; + gboolean ret; + gchar *md5 = NULL; + GError *error = NULL; + CdEdidError rc = CD_EDID_ERROR_OK; + + /* bad input */ + if (edid == NULL || edid_len == 0) { + rc = CD_EDID_ERROR_NO_DATA; + goto out; + } + + /* conect to daemon */ + client = cd_client_new (); + ret = cd_client_connect_sync (client, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("Failed to connect to colord: %s", error->message); + g_error_free (error); + goto out; + } + + /* find device that matches the output EDID */ + md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, + (const gchar *)edid, + (gssize) edid_len); + device = cd_client_find_device_by_property_sync (client, + CD_DEVICE_METADATA_OUTPUT_EDID_MD5, + md5, + NULL, + &error); + if (device == NULL) { + rc = CD_EDID_ERROR_MONITOR_NOT_FOUND; + g_warning ("Failed to find device that matches %s: %s", + md5, error->message); + g_error_free (error); + goto out; + } + + /* read device properties */ + ret = cd_device_connect_sync (device, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("device disappeared: %s", error->message); + g_error_free (error); + goto out; + } + + /* get the default profile for the device */ + profile = cd_device_get_default_profile (device); + if (profile == NULL) { + rc = CD_EDID_ERROR_NO_PROFILE; + g_warning ("No profile for %s: %s", + cd_device_get_id (device), + error->message); + g_error_free (error); + goto out; + } + + /* read profile properties */ + ret = cd_profile_connect_sync (profile, NULL, &error); + if (!ret) { + rc = CD_EDID_ERROR_ACCESS_CONFIG; + g_warning ("profile disappeared: %s", error->message); + g_error_free (error); + goto out; + } + + /* get filename */ + filename = cd_profile_get_filename (profile); + if (filename == NULL) { + rc = CD_EDID_ERROR_INVALID_PROFILE; + goto out; + } + + /* return filename of profile */ + if (profile_fn != NULL) + *profile_fn = strdup (filename); +out: + if (client != NULL) + g_object_unref (client); + if (device != NULL) + g_object_unref (device); + if (profile != NULL) + g_object_unref (profile); + g_free (md5); + return rc; +} diff --git a/lib/compat/cd-edid.h b/lib/compat/cd-edid.h new file mode 100644 index 0000000..b6bff45 --- /dev/null +++ b/lib/compat/cd-edid.h @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2013 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __CD_EDID_H +#define __CD_EDID_H + +#include <glib.h> + +G_BEGIN_DECLS + +/** + * CdEdidError: + * + * The error code. + * NOTE: this enum has to be kept in sync with ucmm_error which is found + * in ucmm/ucmm.h in the ArgyllCMS project. + * + * Since: 0.1.34 + **/ +typedef enum { + CD_EDID_ERROR_OK = 0, + CD_EDID_ERROR_RESOURCE, + CD_EDID_ERROR_INVALID_PROFILE, + CD_EDID_ERROR_NO_PROFILE, + CD_EDID_ERROR_UNUSED1, + CD_EDID_ERROR_NO_DATA, + CD_EDID_ERROR_PROFILE_COPY, + CD_EDID_ERROR_UNUSED2, + CD_EDID_ERROR_ACCESS_CONFIG, + CD_EDID_ERROR_SET_CONFIG, + CD_EDID_ERROR_UNUSED3, + CD_EDID_ERROR_MONITOR_NOT_FOUND, + CD_EDID_ERROR_UNUSED4, + CD_EDID_ERROR_UNUSED5, + CD_EDID_ERROR_LAST, +} CdEdidError; + +/** + * CdEdidScope: + * + * The scope of the profile. + * NOTE: this enum has to be kept in sync with ucmm_scope which is found + * in ucmm/ucmm.h in the ArgyllCMS project. + * + * Since: 0.1.34 + **/ +typedef enum { + CD_EDID_SCOPE_USER, + CD_EDID_SCOPE_SYSTEM, + CD_EDID_SCOPE_LAST +} CdEdidScope; + +CdEdidError cd_edid_install_profile (unsigned char *edid, + int edid_len, + CdEdidScope scope, + char *profile_fn); +CdEdidError cd_edid_remove_profile (unsigned char *edid, + int edid_len, + char *profile_fn); +CdEdidError cd_edid_get_profile (unsigned char *edid, + int edid_len, + char **profile_fn); + +G_END_DECLS + +#endif /* __CD_EDID_H */ diff --git a/lib/compat/test.c b/lib/compat/test.c new file mode 100644 index 0000000..bcf18ec --- /dev/null +++ b/lib/compat/test.c @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2013 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +//gcc -o test test.c cd-edid.c `pkg-config --cflags --libs colord` -I../.. -Wall + +#include <stdlib.h> +#include <stdio.h> + +#include "cd-edid.h" + +int +main (int argc, char *argv[]) +{ + CdEdidError rc; + char *profile = NULL; + gboolean ret; + gchar *edid; + GError *error = NULL; + gsize edid_len = 0; + + /* load EDID blob derived from: + * cat /sys/class/drm/card0-LVDS-1/edid > edid.bin */ + ret = g_file_get_contents ("edid.bin", (gchar**) &edid, &edid_len, &error); + if (!ret) { + g_warning ("Failed to load file: %s", error->message); + g_error_free (error); + return EXIT_FAILURE; + } + + /* test libcolordcompat */ + rc = cd_edid_get_profile ((unsigned char *) edid, edid_len, &profile); + if (rc != CD_EDID_ERROR_OK) { + printf("Failed to get profile, error is %i\n", rc); + return EXIT_FAILURE; + } + printf("Profile to use is %s\n", profile); + free(profile); + + return EXIT_SUCCESS; +} |