summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2013-04-30 11:30:26 +0100
committerRichard Hughes <richard@hughsie.com>2013-05-17 09:39:51 +0100
commit9b955ffc30af9fc68a4e38a5486f996ada08e074 (patch)
treef4b6deb226dd42edb6692623008d567f490fc8ec
parent561dfd01059112539d1afcedc1de64595472ee43 (diff)
downloadcolord-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.am1
-rw-r--r--configure.ac11
-rw-r--r--contrib/colord.spec.in3
-rw-r--r--lib/Makefile.am5
-rw-r--r--lib/compat/Makefile.am42
-rw-r--r--lib/compat/cd-edid.c389
-rw-r--r--lib/compat/cd-edid.h84
-rw-r--r--lib/compat/test.c58
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;
+}