On Wed, Apr 24, 2013 at 02:58:03PM +0100, Richard Hughes wrote: > ICC profiles can now be specified in weston.ini for each output, or a CMS > implementation can optionally loaded from a pluggable module.
Hey Richard, This is cool stuff and I'm happy to see weston gain support for color management. A few comments below. Kristian > --- > configure.ac | 7 +++ > src/Makefile.am | 6 ++- > src/cms.c | 106 +++++++++++++++++++++++++++++++++++++ > src/cms.h | 84 +++++++++++++++++++++++++++++ > src/compositor-drm.c | 147 > ++++++++++++++++++++++++++++++++++++++++++++++++++- > src/compositor.c | 7 +++ > src/compositor.h | 21 ++++++++ > weston.ini | 2 + > 8 files changed, 376 insertions(+), 4 deletions(-) > create mode 100644 src/cms.c > create mode 100644 src/cms.h > > diff --git a/configure.ac b/configure.ac > index d5fea9d..1552d73 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -315,6 +315,13 @@ AC_MSG_NOTICE([Weston's native backend: > $WESTON_NATIVE_BACKEND]) > AC_DEFINE_UNQUOTED([WESTON_NATIVE_BACKEND], ["$WESTON_NATIVE_BACKEND"], > [The default backend to load, if not wayland nor x11.]) > > +PKG_CHECK_MODULES(LCMS, lcms2, > + [have_lcms=yes], [have_lcms=no]) > +if test "x$have_lcms" = xyes; then > + AC_DEFINE(HAVE_LCMS, 1, [Have lcms support]) > +fi > +AM_CONDITIONAL(HAVE_LCMS, [test "x$have_lcms" = xyes]) > + > WAYLAND_SCANNER_RULES(['$(top_srcdir)/protocol']) > > AC_CONFIG_FILES([Makefile > diff --git a/src/Makefile.am b/src/Makefile.am > index d33ebc5..7489086 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -9,8 +9,8 @@ AM_CPPFLAGS = \ > -DIN_WESTON > > weston_LDFLAGS = -export-dynamic > -weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS) > -weston_LDADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \ > +weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS) > $(LCMS_CFLAGS) > +weston_LDADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) $(LCMS_LIBS) \ > $(DLOPEN_LIBS) -lm ../shared/libshared.la > > weston_SOURCES = \ > @@ -20,6 +20,8 @@ weston_SOURCES = \ > compositor.h \ > filter.c \ > filter.h \ > + cms.c \ > + cms.h \ > screenshooter.c \ > screenshooter-protocol.c \ > screenshooter-server-protocol.h \ > diff --git a/src/cms.c b/src/cms.c > new file mode 100644 > index 0000000..1acc680 > --- /dev/null > +++ b/src/cms.c > @@ -0,0 +1,106 @@ > +/* > + * Copyright © 2013 Richard Hughes > + * > + * Permission to use, copy, modify, distribute, and sell this software and > + * its documentation for any purpose is hereby granted without fee, provided > + * that the above copyright notice appear in all copies and that both that > + * copyright notice and this permission notice appear in supporting > + * documentation, and that the name of the copyright holders not be used in > + * advertising or publicity pertaining to distribution of the software > + * without specific, written prior permission. The copyright holders make > + * no representations about the suitability of this software for any > + * purpose. It is provided "as is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS > + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND > + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY > + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER > + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF > + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN > + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#ifdef HAVE_CONFIG_H > +#include <config.h> > +#endif > + > +#include <stdlib.h> > +#include <string.h> > +#include <stdio.h> > + > +#ifdef HAVE_LCMS > +#include <lcms2.h> > +#endif > + > +#include "compositor.h" > +#include "cms.h" > + > +WL_EXPORT void > +weston_cms_set_color_profile(struct weston_output *o, > + struct weston_color_profile *p) > +{ > + if (o->color_profile == p) > + return; > + if (o->color_profile) > + weston_cms_destroy_profile(o->color_profile); > + o->color_profile = p; > + if (o->updated_color_profile) > + o->updated_color_profile(o); > +} > + > +WL_EXPORT int > +weston_cms_output_added(struct weston_output *o, > + enum weston_color_manager_flags flags) > +{ > + struct weston_compositor *ec = o->compositor; > + if (!ec->cms) > + return 0; > + if (!ec->cms->output_added) > + return 0; > + return ec->cms->output_added(o, flags); > +} > + > +WL_EXPORT int > +weston_cms_output_removed(struct weston_output *o) > +{ > + struct weston_compositor *ec = o->compositor; > + if (!ec->cms) > + return 0; > + if (!ec->cms->output_removed) > + return 0; > + return ec->cms->output_removed(o); > +} > + > +WL_EXPORT void > +weston_cms_destroy_profile(struct weston_color_profile *p) > +{ > +#ifdef HAVE_LCMS > + cmsCloseProfile(p->lcms_handle); > +#endif > + free(p->filename); > + free(p); > +} > + > +WL_EXPORT struct weston_color_profile * > +weston_cms_create_profile(const char *filename, > + void *lcms_profile) > +{ > + struct weston_color_profile *p; > + p = calloc(sizeof(struct weston_color_profile), 1); > + p->filename = strdup(filename); > + p->lcms_handle = lcms_profile; > + return p; > +} > + > +WL_EXPORT struct weston_color_profile * > +weston_cms_load_profile(const char *filename) > +{ > + struct weston_color_profile *p = NULL; > +#ifdef HAVE_LCMS > + cmsHPROFILE lcms_profile; > + lcms_profile = cmsOpenProfileFromFile(filename, "r"); > + if (lcms_profile) > + p = weston_cms_create_profile(filename, lcms_profile); > +#endif > + return p; > +} > diff --git a/src/cms.h b/src/cms.h > new file mode 100644 > index 0000000..d99587f > --- /dev/null > +++ b/src/cms.h > @@ -0,0 +1,84 @@ > +/* > + * Copyright © 2013 Richard Hughes > + * > + * Permission to use, copy, modify, distribute, and sell this software and > + * its documentation for any purpose is hereby granted without fee, provided > + * that the above copyright notice appear in all copies and that both that > + * copyright notice and this permission notice appear in supporting > + * documentation, and that the name of the copyright holders not be used in > + * advertising or publicity pertaining to distribution of the software > + * without specific, written prior permission. The copyright holders make > + * no representations about the suitability of this software for any > + * purpose. It is provided "as is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS > + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND > + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY > + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER > + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF > + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN > + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#ifndef _WESTON_CMS_H_ > +#define _WESTON_CMS_H_ > + > +#include "compositor.h" > + > +/* General overview on how to be a CMS plugin: > + * > + * First, some nomenclature: > + * > + * CMF: Color management framework, i.e. "Use foo.icc for device $bar" > + * CMM: Color management module that converts pixel colors, which is > + * usually lcms2 on any modern OS. > + * CMS: Color management system that encompasses both a CMF and CMM. > + * ICC: International Color Consortium, the people that define the > + * binary encoding of a .icc file. > + * VCGT: Video Card Gamma Tag. An Apple extension to the ICC > specification > + * that allows the calibration state to be stored in the ICC > profile > + * Output: Physical port with a display attached, e.g. LVDS1 > + * > + * As a CMF is probably something you don't want or need on an embeded > install > + * these functions will not be called if the icc_profile key is set for a > + * specific [output] section in weston.ini > + * > + * Most desktop environments want the CMF to decide what profile to use in > + * different situations, so that displays can be profiled and also so that > + * the ICC profiles can be changed at runtime depending on the task or > ambient > + * environment. > + * > + * The CMF can be selected using the 'cms' key in the [core] section. > + * Specifying multiple CMFs will not work. > + * > + * The general idea is the compositor creates an output which is registered > + * with the CMS using weston_cms_output_added(). This is expected to call > + * the ->updated_color_profile() vfunc on the output with the prepared object > + * of type weston_color_profile, or NULL if there is no color profile to > apply. > + * > + * If the CMF can detect that the assigned ICC profile has changed for a > + * specific output, then it can call the ->updated_color_profile() vfunc at > any > + * time until weston_cms_output_removed() is called. > + * > + * The updated_color_profile() vfunc is expected to set the output > calibration > + * state, typically by uploading the VCGT data to the graphics card using > + * drmModeCrtcSetGamma() > + */ > + > +void > +weston_cms_set_color_profile(struct weston_output *o, > + struct weston_color_profile *p); > +int > +weston_cms_output_added(struct weston_output *o, > + enum weston_color_manager_flags flags); > +int > +weston_cms_output_removed(struct weston_output *o); > +struct weston_color_profile * > +weston_cms_create_profile(const char *filename, > + void *lcms_profile); > +struct weston_color_profile * > +weston_cms_load_profile(const char *filename); > +void > +weston_cms_destroy_profile(struct weston_color_profile *p); > + > +#endif > diff --git a/src/compositor-drm.c b/src/compositor-drm.c > index c8016cd..15f99c3 100644 > --- a/src/compositor-drm.c > +++ b/src/compositor-drm.c > @@ -21,6 +21,10 @@ > * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > */ > > +#ifdef HAVE_CONFIG_H > +#include <config.h> > +#endif > + > #define _GNU_SOURCE > > #include <errno.h> > @@ -33,6 +37,10 @@ > #include <assert.h> > #include <sys/mman.h> > > +#ifdef HAVE_LCMS > +#include <lcms2.h> > +#endif > + > #include <xf86drm.h> > #include <xf86drmMode.h> > #include <drm_fourcc.h> > @@ -46,11 +54,13 @@ > #include "pixman-renderer.h" > #include "udev-seat.h" > #include "launcher-util.h" > +#include "cms.h" > > static int option_current_mode = 0; > static char *output_name; > static char *output_mode; > static char *output_transform; > +static char *output_icc_profile; > static struct wl_list configured_output_list; > > enum output_config { > @@ -70,6 +80,7 @@ struct drm_configured_output { > drmModeModeInfo crtc_mode; > enum output_config config; > struct wl_list link; > + struct weston_color_profile *color_profile; > }; > > struct drm_compositor { > @@ -545,6 +556,95 @@ drm_output_render(struct drm_output *output, > pixman_region32_t *damage) > } > > static void > +drm_output_gamma_reset(struct drm_compositor *compositor, > + struct drm_output *output) > +{ > + int i; > + int ret; > + int size; > + uint16_t *blue = NULL; > + uint16_t *green = NULL; > + uint16_t *red = NULL; > + uint32_t tmp; > + > + if (!output->original_crtc) > + return; > + > + size = output->original_crtc->gamma_size; > + red = calloc(sizeof(uint16_t), size); > + green = calloc(sizeof(uint16_t), size); > + blue = calloc(sizeof(uint16_t), size); > + for (i = 0; i < size; i++) { > + tmp = (uint32_t) 0xffff * (uint32_t) i / (uint32_t) (size - 1); > + red[i] = green[i] = blue[i] = tmp; > + } > + ret = drmModeCrtcSetGamma(compositor->drm.fd, > + output->crtc_id, > + size, > + red, green, blue); > + if (ret) > + weston_log("reset gamma failed: %m\n"); > + > + free(red); > + free(green); > + free(blue); > +} > + > +static void > +drm_output_updated_color_profile(struct weston_output *output_base) > +{ Could we move the LCMS code to a built-in or make a lcms.so module? I think we don't need cms.c/h (see below for details), but just the lcms code in its own module. And then make the weston_output interface be output->set_gamma(), since that's all the output really supports? > +#ifdef HAVE_LCMS > + struct drm_output *output = (struct drm_output *) output_base; > + struct drm_compositor *compositor = (struct drm_compositor *) > output->base.compositor; > + cmsFloat32Number in; > + const cmsToneCurve **vcgt; > + int i; > + int rc; > + int size; > + uint16_t *red = NULL; > + uint16_t *green = NULL; > + uint16_t *blue = NULL; > + > + /* anything to apply */ > + if (!output->base.color_profile) { > + drm_output_gamma_reset (compositor, output); > + return; > + } > + if (!output->original_crtc) > + return; > + weston_log("Using ICC profile %s\n", > + output->base.color_profile->filename); > + > + vcgt = cmsReadTag (output->base.color_profile->lcms_handle, > cmsSigVcgtTag); > + if (vcgt == NULL || vcgt[0] == NULL) { > + drm_output_gamma_reset(compositor, output); > + return; > + } > + > + size = output->original_crtc->gamma_size; > + red = calloc(sizeof(uint16_t), size); > + green = calloc(sizeof(uint16_t), size); > + blue = calloc(sizeof(uint16_t), size); > + for (i = 0; i < size; i++) { > + in = (cmsFloat32Number) i / (cmsFloat32Number) (size - 1); > + red[i] = cmsEvalToneCurveFloat(vcgt[0], in) * (double) 0xffff; > + green[i] = cmsEvalToneCurveFloat(vcgt[1], in) * (double) 0xffff; > + blue[i] = cmsEvalToneCurveFloat(vcgt[2], in) * (double) 0xffff; > + } > + rc = drmModeCrtcSetGamma(compositor->drm.fd, > + output->crtc_id, > + size, > + red, green, blue); > + if (rc) > + weston_log("set gamma failed: %m\n"); > + > + free(red); > + free(green); > + free(blue); > +#endif > +} > + > +static void > drm_output_repaint(struct weston_output *output_base, > pixman_region32_t *damage) > { > @@ -570,6 +670,7 @@ drm_output_repaint(struct weston_output *output_base, > weston_log("set mode failed: %m\n"); > return; > } > + drm_output_updated_color_profile(output_base); Doesn't this set the gamma ramp every time we repaint? > } > > if (drmModePageFlip(compositor->drm.fd, output->crtc_id, > @@ -1026,7 +1127,11 @@ drm_output_destroy(struct weston_output *output_base) > /* Turn off hardware cursor */ > drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0); > > + /* Remove CMS device */ > + weston_cms_output_removed(&output->base); I'd like to add a destroy_signal to the weston_output and then let the cms hook into that instead. > /* Restore original CRTC state */ > + drm_output_gamma_reset (c, output); > drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id, > origcrtc->x, origcrtc->y, > &output->connector_id, 1, &origcrtc->mode); > @@ -1648,6 +1753,7 @@ create_output_for_connector(struct drm_compositor *ec, > int i; > char name[32]; > const char *type_name; > + enum weston_color_manager_flags cm_flags = 0; > > i = find_crtc_for_connector(ec, resources, connector); > if (i < 0) { > @@ -1787,6 +1893,18 @@ create_output_for_connector(struct drm_compositor *ec, > output->base.backlight_current = drm_get_backlight(output); > } > > + /* get the ICC profile for the device from the CMS, *unless* there is > + * a hardcoded profile specified in [output] */ > + if (o && o->color_profile) { > + weston_log("Using hardcoded ICC profile %s\n", > + o->color_profile->filename); > + weston_cms_set_color_profile(&output->base, o->color_profile); > + } else { > + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) > + cm_flags &= WESTON_COLOR_MANAGER_FLAG_OUTPUT_INTERNAL; > + weston_cms_output_added(&output->base, cm_flags); > + } > + Likewise, we should add a output_created_signal (similar to seat_created_signal) and the cms should hook into that instead of calling into the cms here from compositor-drm.c. As for the cm_flags and color profile, we'll need to make those weston_output fields and set them before emitting the signal. > wl_list_insert(ec->base.output_list.prev, &output->base.link); > > find_and_parse_output_edid(ec, output, connector); > @@ -1798,6 +1916,7 @@ create_output_for_connector(struct drm_compositor *ec, > output->base.assign_planes = drm_assign_planes; > output->base.set_dpms = drm_set_dpms; > output->base.switch_mode = drm_output_switch_mode; > + output->base.updated_color_profile = drm_output_updated_color_profile; > > weston_plane_init(&output->cursor_plane, 0, 0); > weston_plane_init(&output->fb_plane, 0, 0); > @@ -2098,6 +2217,7 @@ drm_restore(struct weston_compositor *ec) > static void > drm_free_configured_output(struct drm_configured_output *output) > { > + weston_cms_destroy_profile(output->color_profile); > free(output->name); > free(output->mode); > free(output); > @@ -2565,21 +2685,39 @@ drm_output_set_transform(struct drm_configured_output > *output) > } > > static void > +drm_output_set_icc_profile(struct drm_configured_output *output) > +{ > + if (!output_icc_profile) { > + output->color_profile = NULL; > + return; > + } > + output->color_profile = weston_cms_load_profile(output_icc_profile); > + if (output->color_profile) { > + weston_log("Using hardcoded profile \"%s\" for output %s\n", > + output_icc_profile, output_name); > + } else { > + weston_log("Failed to load profile \"%s\" for output %s\n", > + output_icc_profile, output_name); > + } > +} compositor-drm.c (currently) has to parse the output section, but this part should be done by the cms plugin. All we need to do here then is to set the base weston_output fields so that the cms plugin can access it when it gets the output_created_signal. > +static void > output_section_done(void *data) > { > struct drm_configured_output *output; > > output = malloc(sizeof *output); > > - if (!output || !output_name || (output_name[0] == 'X') || > - (!output_mode && !output_transform)) { Keep the 'X' test, we have the convention that outputs named Xsomething are X windows. > + if (!output || !output_name) { > free(output_name); > free(output_mode); > free(output_transform); > + free(output_icc_profile); > free(output); > output_name = NULL; > output_mode = NULL; > output_transform = NULL; > + output_icc_profile = NULL; > return; > } > > @@ -2607,12 +2745,16 @@ output_section_done(void *data) > } > > drm_output_set_transform(output); > + drm_output_set_icc_profile(output); > > wl_list_insert(&configured_output_list, &output->link); > > if (output_transform) > free(output_transform); > output_transform = NULL; > + if (output_icc_profile) > + free(output_icc_profile); > + output_icc_profile = NULL; > } > > WL_EXPORT struct weston_compositor * > @@ -2638,6 +2780,7 @@ backend_init(struct wl_display *display, int *argc, > char *argv[], > { "name", CONFIG_KEY_STRING, &output_name }, > { "mode", CONFIG_KEY_STRING, &output_mode }, > { "transform", CONFIG_KEY_STRING, &output_transform }, > + { "icc_profile", CONFIG_KEY_STRING, &output_icc_profile }, > }; > > const struct config_section config_section[] = { > diff --git a/src/compositor.c b/src/compositor.c > index 693df2c..5047471 100644 > --- a/src/compositor.c > +++ b/src/compositor.c > @@ -56,6 +56,7 @@ > > #include <wayland-server.h> > #include "compositor.h" > +#include "cms.h" > #include "../shared/os-compatibility.h" > #include "git-version.h" > #include "version.h" > @@ -2906,6 +2907,8 @@ weston_output_destroy(struct weston_output *output) > { > struct weston_compositor *c = output->compositor; > > + weston_cms_destroy_profile(output->color_profile); > + > pixman_region32_fini(&output->region); > pixman_region32_fini(&output->previous_damage); > output->compositor->output_id_pool &= ~(1 << output->id); > @@ -3526,6 +3529,7 @@ int main(int argc, char *argv[]) > int i; > char *backend = NULL; > const char *modules = "desktop-shell.so", *option_modules = NULL; > + const char *cms_modules = NULL; > char *log = NULL; > int32_t idle_time = 300; > int32_t help = 0; > @@ -3535,6 +3539,7 @@ int main(int argc, char *argv[]) > > const struct config_key core_config_keys[] = { > { "modules", CONFIG_KEY_STRING, &modules }, > + { "cms", CONFIG_KEY_STRING, &cms_modules }, > }; > > const struct config_section cs[] = { > @@ -3617,6 +3622,8 @@ int main(int argc, char *argv[]) > > setenv("WAYLAND_DISPLAY", socket_name, 1); > > + if (load_modules(ec, cms_modules, &argc, argv, config_file) < 0) > + goto out; > if (load_modules(ec, modules, &argc, argv, config_file) < 0) > goto out; It should be fine to just add the cms module to the module= key in the ini file, eg: modules=xwayland.so,simple-cms.so > if (load_modules(ec, option_modules, &argc, argv, config_file) < 0) > diff --git a/src/compositor.h b/src/compositor.h > index eb8ad82..81d7035 100644 > --- a/src/compositor.h > +++ b/src/compositor.h > @@ -154,6 +154,11 @@ enum dpms_enum { > WESTON_DPMS_OFF > }; > > +struct weston_color_profile { > + char *filename; > + void *lcms_handle; > +}; > + > struct weston_output { > uint32_t id; > > @@ -197,6 +202,9 @@ struct weston_output { > uint32_t backlight_current; > void (*set_backlight)(struct weston_output *output, uint32_t value); > void (*set_dpms)(struct weston_output *output, enum dpms_enum level); > + > + struct weston_color_profile *color_profile; > + void (*updated_color_profile)(struct weston_output *output); This one should just be void (*set_gamma)(output, r, g, b) and we can advertise the size of the gamma ramp as a field in weston_output or just always assume 256 steps and uint32_t values. > }; > > struct weston_xkb_info { > @@ -297,6 +305,17 @@ struct weston_renderer { > void (*destroy)(struct weston_compositor *ec); > }; > > +enum weston_color_manager_flags { > + WESTON_COLOR_MANAGER_FLAG_OUTPUT_INTERNAL = 1, > +}; > + > +struct weston_color_manager { > + void (*destroy) (struct weston_compositor *c); > + int (*output_added) (struct weston_output *o, > + enum weston_color_manager_flags flags); > + int (*output_removed) (struct weston_output *o); > +}; I don't think we'll need this struct now. The destroy vfunc should be listener on the weston_compositor::destroy_signal instead. > struct weston_compositor { > struct wl_signal destroy_signal; > > @@ -360,6 +379,8 @@ struct weston_compositor { > struct xkb_rule_names xkb_names; > struct xkb_context *xkb_context; > struct weston_xkb_info xkb_info; > + > + struct weston_color_manager *cms; and this one we typically look up using wl_signal_get(signal, notify_func) and then use container_of to go from the embedded destroy wl_listener to the cms struct. > }; > > struct weston_buffer_reference { > diff --git a/weston.ini b/weston.ini > index c6cff76..639a0e8 100644 > --- a/weston.ini > +++ b/weston.ini > @@ -1,5 +1,6 @@ > [core] > #modules=desktop-shell.so,xwayland.so > +#cms=colord.so > > [shell] > background-image=/usr/share/backgrounds/gnome/Aqua.jpg > @@ -45,6 +46,7 @@ path=/usr/libexec/weston-keyboard > #name=LVDS1 > #mode=1680x1050 > #transform=90 > +#icc_profile=/usr/share/color/icc/colord/Bluish.icc > > #[output] > #name=VGA1 > -- > 1.8.2 > > _______________________________________________ > wayland-devel mailing list > wayland-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/wayland-devel _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel