Commit 64ad9a61 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Introduce ColorManager component

This change introduces a new component - ColorManager that is
responsible for color management stuff.

At the moment, it's very naive. It is useful only for updating gamma
ramps. But in the future, it will be extended with more CMS-related
features.

The ColorManager depends on lcms2 library. This is an optional
dependency. If lcms2 is not installed, the color manager won't be built.

This also fixes the issue where colord and nightcolor overwrite each
other's gamma ramps. With this change, the ColorManager will resolve the
conflict between two.
parent b06fb6b0
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2017 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
namespace KWin
{
/**
* Whitepoint values for temperatures at 100K intervals.
* These will be interpolated for the actual temperature.
* This table was provided by Ingo Thies, 2013.
* See the following file for more information:
* https://github.com/jonls/redshift/blob/master/README-colorramp
*/
static const float blackbodyColor[] = {
1.00000000, 0.18172716, 0.00000000, /* 1000K */
1.00000000, 0.25503671, 0.00000000, /* 1100K */
1.00000000, 0.30942099, 0.00000000, /* 1200K */
1.00000000, 0.35357379, 0.00000000, /* ... */
1.00000000, 0.39091524, 0.00000000,
1.00000000, 0.42322816, 0.00000000,
1.00000000, 0.45159884, 0.00000000,
1.00000000, 0.47675916, 0.00000000,
1.00000000, 0.49923747, 0.00000000,
1.00000000, 0.51943421, 0.00000000,
1.00000000, 0.54360078, 0.08679949, /* 2000K */
1.00000000, 0.56618736, 0.14065513,
1.00000000, 0.58734976, 0.18362641,
1.00000000, 0.60724493, 0.22137978,
1.00000000, 0.62600248, 0.25591950,
1.00000000, 0.64373109, 0.28819679,
1.00000000, 0.66052319, 0.31873863,
1.00000000, 0.67645822, 0.34786758,
1.00000000, 0.69160518, 0.37579588,
1.00000000, 0.70602449, 0.40267128,
1.00000000, 0.71976951, 0.42860152, /* 3000K */
1.00000000, 0.73288760, 0.45366838,
1.00000000, 0.74542112, 0.47793608,
1.00000000, 0.75740814, 0.50145662,
1.00000000, 0.76888303, 0.52427322,
1.00000000, 0.77987699, 0.54642268,
1.00000000, 0.79041843, 0.56793692,
1.00000000, 0.80053332, 0.58884417,
1.00000000, 0.81024551, 0.60916971,
1.00000000, 0.81957693, 0.62893653,
1.00000000, 0.82854786, 0.64816570, /* 4000K */
1.00000000, 0.83717703, 0.66687674,
1.00000000, 0.84548188, 0.68508786,
1.00000000, 0.85347859, 0.70281616,
1.00000000, 0.86118227, 0.72007777,
1.00000000, 0.86860704, 0.73688797, /* 4500K */
1.00000000, 0.87576611, 0.75326132,
1.00000000, 0.88267187, 0.76921169,
1.00000000, 0.88933596, 0.78475236,
1.00000000, 0.89576933, 0.79989606,
1.00000000, 0.90198230, 0.81465502, /* 5000K */
1.00000000, 0.90963069, 0.82838210,
1.00000000, 0.91710889, 0.84190889,
1.00000000, 0.92441842, 0.85523742,
1.00000000, 0.93156127, 0.86836903,
1.00000000, 0.93853986, 0.88130458,
1.00000000, 0.94535695, 0.89404470,
1.00000000, 0.95201559, 0.90658983,
1.00000000, 0.95851906, 0.91894041,
1.00000000, 0.96487079, 0.93109690,
1.00000000, 0.97107439, 0.94305985, /* 6000K */
1.00000000, 0.97713351, 0.95482993,
1.00000000, 0.98305189, 0.96640795,
1.00000000, 0.98883326, 0.97779486,
1.00000000, 0.99448139, 0.98899179,
1.00000000, 1.00000000, 1.00000000, /* 6500K */
0.98947904, 0.99348723, 1.00000000,
0.97940448, 0.98722715, 1.00000000,
0.96975025, 0.98120637, 1.00000000,
0.96049223, 0.97541240, 1.00000000,
0.95160805, 0.96983355, 1.00000000, /* 7000K */
0.94303638, 0.96443333, 1.00000000,
0.93480451, 0.95923080, 1.00000000,
0.92689056, 0.95421394, 1.00000000,
0.91927697, 0.94937330, 1.00000000,
0.91194747, 0.94470005, 1.00000000,
0.90488690, 0.94018594, 1.00000000,
0.89808115, 0.93582323, 1.00000000,
0.89151710, 0.93160469, 1.00000000,
0.88518247, 0.92752354, 1.00000000,
0.87906581, 0.92357340, 1.00000000, /* 8000K */
0.87315640, 0.91974827, 1.00000000,
0.86744421, 0.91604254, 1.00000000,
0.86191983, 0.91245088, 1.00000000,
0.85657444, 0.90896831, 1.00000000,
0.85139976, 0.90559011, 1.00000000,
0.84638799, 0.90231183, 1.00000000,
0.84153180, 0.89912926, 1.00000000,
0.83682430, 0.89603843, 1.00000000,
0.83225897, 0.89303558, 1.00000000,
0.82782969, 0.89011714, 1.00000000, /* 9000K */
0.82353066, 0.88727974, 1.00000000,
0.81935641, 0.88452017, 1.00000000,
0.81530175, 0.88183541, 1.00000000,
0.81136180, 0.87922257, 1.00000000,
0.80753191, 0.87667891, 1.00000000,
0.80380769, 0.87420182, 1.00000000,
0.80018497, 0.87178882, 1.00000000,
0.79665980, 0.86943756, 1.00000000,
0.79322843, 0.86714579, 1.00000000,
0.78988728, 0.86491137, 1.00000000, /* 10000K */
0.78663296, 0.86273225, 1.00000000,
0.78346225, 0.86060650, 1.00000000,
0.78037207, 0.85853224, 1.00000000,
0.77735950, 0.85650771, 1.00000000,
0.77442176, 0.85453121, 1.00000000,
0.77155617, 0.85260112, 1.00000000,
0.76876022, 0.85071588, 1.00000000,
0.76603147, 0.84887402, 1.00000000,
0.76336762, 0.84707411, 1.00000000,
0.76076645, 0.84531479, 1.00000000, /* 11000K */
0.75822586, 0.84359476, 1.00000000,
0.75574383, 0.84191277, 1.00000000,
0.75331843, 0.84026762, 1.00000000,
0.75094780, 0.83865816, 1.00000000,
0.74863017, 0.83708329, 1.00000000,
0.74636386, 0.83554194, 1.00000000,
0.74414722, 0.83403311, 1.00000000,
0.74197871, 0.83255582, 1.00000000,
0.73985682, 0.83110912, 1.00000000,
0.73778012, 0.82969211, 1.00000000, /* 12000K */
0.73574723, 0.82830393, 1.00000000,
0.73375683, 0.82694373, 1.00000000,
0.73180765, 0.82561071, 1.00000000,
0.72989845, 0.82430410, 1.00000000,
0.72802807, 0.82302316, 1.00000000,
0.72619537, 0.82176715, 1.00000000,
0.72439927, 0.82053539, 1.00000000,
0.72263872, 0.81932722, 1.00000000,
0.72091270, 0.81814197, 1.00000000,
0.71922025, 0.81697905, 1.00000000, /* 13000K */
0.71756043, 0.81583783, 1.00000000,
0.71593234, 0.81471775, 1.00000000,
0.71433510, 0.81361825, 1.00000000,
0.71276788, 0.81253878, 1.00000000,
0.71122987, 0.81147883, 1.00000000,
0.70972029, 0.81043789, 1.00000000,
0.70823838, 0.80941546, 1.00000000,
0.70678342, 0.80841109, 1.00000000,
0.70535469, 0.80742432, 1.00000000,
0.70395153, 0.80645469, 1.00000000, /* 14000K */
0.70257327, 0.80550180, 1.00000000,
0.70121928, 0.80456522, 1.00000000,
0.69988894, 0.80364455, 1.00000000,
0.69858167, 0.80273941, 1.00000000,
0.69729688, 0.80184943, 1.00000000,
0.69603402, 0.80097423, 1.00000000,
0.69479255, 0.80011347, 1.00000000,
0.69357196, 0.79926681, 1.00000000,
0.69237173, 0.79843391, 1.00000000,
0.69119138, 0.79761446, 1.00000000, /* 15000K */
0.69003044, 0.79680814, 1.00000000,
0.68888844, 0.79601466, 1.00000000,
0.68776494, 0.79523371, 1.00000000,
0.68665951, 0.79446502, 1.00000000,
0.68557173, 0.79370830, 1.00000000,
0.68450119, 0.79296330, 1.00000000,
0.68344751, 0.79222975, 1.00000000,
0.68241029, 0.79150740, 1.00000000,
0.68138918, 0.79079600, 1.00000000,
0.68038380, 0.79009531, 1.00000000, /* 16000K */
0.67939381, 0.78940511, 1.00000000,
0.67841888, 0.78872517, 1.00000000,
0.67745866, 0.78805526, 1.00000000,
0.67651284, 0.78739518, 1.00000000,
0.67558112, 0.78674472, 1.00000000,
0.67466317, 0.78610368, 1.00000000,
0.67375872, 0.78547186, 1.00000000,
0.67286748, 0.78484907, 1.00000000,
0.67198916, 0.78423512, 1.00000000,
0.67112350, 0.78362984, 1.00000000, /* 17000K */
0.67027024, 0.78303305, 1.00000000,
0.66942911, 0.78244457, 1.00000000,
0.66859988, 0.78186425, 1.00000000,
0.66778228, 0.78129191, 1.00000000,
0.66697610, 0.78072740, 1.00000000,
0.66618110, 0.78017057, 1.00000000,
0.66539706, 0.77962127, 1.00000000,
0.66462376, 0.77907934, 1.00000000,
0.66386098, 0.77854465, 1.00000000,
0.66310852, 0.77801705, 1.00000000, /* 18000K */
0.66236618, 0.77749642, 1.00000000,
0.66163375, 0.77698261, 1.00000000,
0.66091106, 0.77647551, 1.00000000,
0.66019791, 0.77597498, 1.00000000,
0.65949412, 0.77548090, 1.00000000,
0.65879952, 0.77499315, 1.00000000,
0.65811392, 0.77451161, 1.00000000,
0.65743716, 0.77403618, 1.00000000,
0.65676908, 0.77356673, 1.00000000,
0.65610952, 0.77310316, 1.00000000, /* 19000K */
0.65545831, 0.77264537, 1.00000000,
0.65481530, 0.77219324, 1.00000000,
0.65418036, 0.77174669, 1.00000000,
0.65355332, 0.77130560, 1.00000000,
0.65293404, 0.77086988, 1.00000000,
0.65232240, 0.77043944, 1.00000000,
0.65171824, 0.77001419, 1.00000000,
0.65112144, 0.76959404, 1.00000000,
0.65053187, 0.76917889, 1.00000000,
0.64994941, 0.76876866, 1.00000000, /* 20000K */
0.64937392, 0.76836326, 1.00000000,
0.64880528, 0.76796263, 1.00000000,
0.64824339, 0.76756666, 1.00000000,
0.64768812, 0.76717529, 1.00000000,
0.64713935, 0.76678844, 1.00000000,
0.64659699, 0.76640603, 1.00000000,
0.64606092, 0.76602798, 1.00000000,
0.64553103, 0.76565424, 1.00000000,
0.64500722, 0.76528472, 1.00000000,
0.64448939, 0.76491935, 1.00000000, /* 21000K */
0.64397745, 0.76455808, 1.00000000,
0.64347129, 0.76420082, 1.00000000,
0.64297081, 0.76384753, 1.00000000,
0.64247594, 0.76349813, 1.00000000,
0.64198657, 0.76315256, 1.00000000,
0.64150261, 0.76281076, 1.00000000,
0.64102399, 0.76247267, 1.00000000,
0.64055061, 0.76213824, 1.00000000,
0.64008239, 0.76180740, 1.00000000,
0.63961926, 0.76148010, 1.00000000, /* 22000K */
0.63916112, 0.76115628, 1.00000000,
0.63870790, 0.76083590, 1.00000000,
0.63825953, 0.76051890, 1.00000000,
0.63781592, 0.76020522, 1.00000000,
0.63737701, 0.75989482, 1.00000000,
0.63694273, 0.75958764, 1.00000000,
0.63651299, 0.75928365, 1.00000000,
0.63608774, 0.75898278, 1.00000000,
0.63566691, 0.75868499, 1.00000000,
0.63525042, 0.75839025, 1.00000000, /* 23000K */
0.63483822, 0.75809849, 1.00000000,
0.63443023, 0.75780969, 1.00000000,
0.63402641, 0.75752379, 1.00000000,
0.63362667, 0.75724075, 1.00000000,
0.63323097, 0.75696053, 1.00000000,
0.63283925, 0.75668310, 1.00000000,
0.63245144, 0.75640840, 1.00000000,
0.63206749, 0.75613641, 1.00000000,
0.63168735, 0.75586707, 1.00000000,
0.63131096, 0.75560036, 1.00000000, /* 24000K */
0.63093826, 0.75533624, 1.00000000,
0.63056920, 0.75507467, 1.00000000,
0.63020374, 0.75481562, 1.00000000,
0.62984181, 0.75455904, 1.00000000,
0.62948337, 0.75430491, 1.00000000,
0.62912838, 0.75405319, 1.00000000,
0.62877678, 0.75380385, 1.00000000,
0.62842852, 0.75355685, 1.00000000,
0.62808356, 0.75331217, 1.00000000,
0.62774186, 0.75306977, 1.00000000, /* 25000K */
0.62740336, 0.75282962, 1.00000000
};
} // namespace KWin
...@@ -241,7 +241,7 @@ set_package_properties(lcms2 PROPERTIES ...@@ -241,7 +241,7 @@ set_package_properties(lcms2 PROPERTIES
URL "http://www.littlecms.com" URL "http://www.littlecms.com"
TYPE OPTIONAL TYPE OPTIONAL
) )
set(HAVE_LCMS2 ${lcms2_FOUND}) add_feature_info("lcms2" lcms2_FOUND "Required for the color management system")
# All the required XCB components # All the required XCB components
find_package(XCB 1.10 REQUIRED COMPONENTS find_package(XCB 1.10 REQUIRED COMPONENTS
...@@ -350,6 +350,7 @@ option(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON) ...@@ -350,6 +350,7 @@ option(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON)
option(KWIN_BUILD_XRENDER_COMPOSITING "Enable building of KWin with XRender Compositing support" ON) option(KWIN_BUILD_XRENDER_COMPOSITING "Enable building of KWin with XRender Compositing support" ON)
cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "KF5Activities_FOUND" OFF) cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "KF5Activities_FOUND" OFF)
cmake_dependent_option(KWIN_BUILD_RUNNERS "Enable building of KWin with krunner support" ON "KF5Runner_FOUND" OFF) cmake_dependent_option(KWIN_BUILD_RUNNERS "Enable building of KWin with krunner support" ON "KF5Runner_FOUND" OFF)
cmake_dependent_option(KWIN_BUILD_CMS "Enable building of KWin with CMS" ON "lcms2_FOUND" OFF)
# Binary name of KWin # Binary name of KWin
set(KWIN_NAME "kwin") set(KWIN_NAME "kwin")
...@@ -709,6 +710,14 @@ set_target_properties(kwin PROPERTIES ...@@ -709,6 +710,14 @@ set_target_properties(kwin PROPERTIES
target_link_libraries(kwin ${kwinLibs} kwinglutils ${epoxy_LIBRARY}) target_link_libraries(kwin ${kwinLibs} kwinglutils ${epoxy_LIBRARY})
if (KWIN_BUILD_CMS)
target_sources(kwin PRIVATE
colordevice.cpp
colormanager.cpp
)
target_link_libraries(kwin lcms2::lcms2)
endif()
generate_export_header(kwin EXPORT_FILE_NAME kwin_export.h) generate_export_header(kwin EXPORT_FILE_NAME kwin_export.h)
if(CMAKE_SYSTEM MATCHES "FreeBSD") if(CMAKE_SYSTEM MATCHES "FreeBSD")
......
...@@ -89,7 +89,6 @@ integrationTest(WAYLAND_ONLY NAME testLayerShellV1Client SRCS layershellv1client ...@@ -89,7 +89,6 @@ integrationTest(WAYLAND_ONLY NAME testLayerShellV1Client SRCS layershellv1client
integrationTest(WAYLAND_ONLY NAME testVirtualDesktop SRCS virtual_desktop_test.cpp) integrationTest(WAYLAND_ONLY NAME testVirtualDesktop SRCS virtual_desktop_test.cpp)
integrationTest(WAYLAND_ONLY NAME testXdgShellClientRules SRCS xdgshellclient_rules_test.cpp) integrationTest(WAYLAND_ONLY NAME testXdgShellClientRules SRCS xdgshellclient_rules_test.cpp)
integrationTest(WAYLAND_ONLY NAME testIdleInhibition SRCS idle_inhibition_test.cpp) integrationTest(WAYLAND_ONLY NAME testIdleInhibition SRCS idle_inhibition_test.cpp)
integrationTest(WAYLAND_ONLY NAME testNightColor SRCS nightcolor_test.cpp LIBS KWinNightColorPlugin)
integrationTest(WAYLAND_ONLY NAME testDontCrashCursorPhysicalSizeEmpty SRCS dont_crash_cursor_physical_size_empty.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashCursorPhysicalSizeEmpty SRCS dont_crash_cursor_physical_size_empty.cpp)
integrationTest(WAYLAND_ONLY NAME testDontCrashReinitializeCompositor SRCS dont_crash_reinitialize_compositor.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashReinitializeCompositor SRCS dont_crash_reinitialize_compositor.cpp)
integrationTest(WAYLAND_ONLY NAME testNoGlobalShortcuts SRCS no_global_shortcuts_test.cpp) integrationTest(WAYLAND_ONLY NAME testNoGlobalShortcuts SRCS no_global_shortcuts_test.cpp)
...@@ -98,6 +97,10 @@ integrationTest(WAYLAND_ONLY NAME testPlacement SRCS placement_test.cpp) ...@@ -98,6 +97,10 @@ integrationTest(WAYLAND_ONLY NAME testPlacement SRCS placement_test.cpp)
integrationTest(WAYLAND_ONLY NAME testActivation SRCS activation_test.cpp) integrationTest(WAYLAND_ONLY NAME testActivation SRCS activation_test.cpp)
integrationTest(WAYLAND_ONLY NAME testInputMethod SRCS inputmethod_test.cpp) integrationTest(WAYLAND_ONLY NAME testInputMethod SRCS inputmethod_test.cpp)
if (KWIN_BUILD_CMS)
integrationTest(WAYLAND_ONLY NAME testNightColor SRCS nightcolor_test.cpp LIBS KWinNightColorPlugin)
endif()
if (XCB_ICCCM_FOUND) if (XCB_ICCCM_FOUND)
integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM)
integrationTest(NAME testStruts SRCS struts_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testStruts SRCS struts_test.cpp LIBS XCB::ICCCM)
......
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "colordevice.h"
#include "abstract_output.h"
#include "utils.h"
#include "3rdparty/colortemperature.h"
#include <QTimer>
#include <lcms2.h>
namespace KWin
{
template <typename T>
struct CmsDeleter;
template <typename T>
using CmsScopedPointer = QScopedPointer<T, CmsDeleter<T>>;
template <>
struct CmsDeleter<cmsPipeline>
{
static inline void cleanup(cmsPipeline *pipeline)
{
if (pipeline) {
cmsPipelineFree(pipeline);
}
}
};
template <>
struct CmsDeleter<cmsStage>
{
static inline void cleanup(cmsStage *stage)
{
if (stage) {
cmsStageFree(stage);
}
}
};
template <>
struct CmsDeleter<cmsToneCurve>
{
static inline void cleanup(cmsToneCurve *toneCurve)
{
if (toneCurve) {
cmsFreeToneCurve(toneCurve);
}
}
};
class ColorDevicePrivate
{
public:
enum DirtyToneCurveBit {
DirtyTemperatureToneCurve = 0x1,
DirtyBrightnessToneCurve = 0x2,
DirtyCalibrationToneCurve = 0x4,
};
Q_DECLARE_FLAGS(DirtyToneCurves, DirtyToneCurveBit)
void rebuildPipeline();
void unlinkPipeline();
void updateTemperatureToneCurves();
void updateBrightnessToneCurves();
void updateCalibrationToneCurves();
AbstractOutput *output;
DirtyToneCurves dirtyCurves;
QTimer *updateTimer;
QString profile;
uint brightness = 100;
uint temperature = 6500;
CmsScopedPointer<cmsStage> temperatureStage;
CmsScopedPointer<cmsStage> brightnessStage;
CmsScopedPointer<cmsStage> calibrationStage;
CmsScopedPointer<cmsPipeline> pipeline;
};
void ColorDevicePrivate::rebuildPipeline()
{
if (!pipeline) {
pipeline.reset(cmsPipelineAlloc(nullptr, 3, 3));
}
unlinkPipeline();
if (dirtyCurves & DirtyCalibrationToneCurve) {
updateCalibrationToneCurves();
}
if (dirtyCurves & DirtyBrightnessToneCurve) {
updateBrightnessToneCurves();
}
if (dirtyCurves & DirtyTemperatureToneCurve) {
updateTemperatureToneCurves();
}
dirtyCurves = DirtyToneCurves();
if (calibrationStage) {
if (!cmsPipelineInsertStage(pipeline.data(), cmsAT_END, calibrationStage.data())) {
qCWarning(KWIN_CORE) << "Failed to insert the color calibration pipeline stage";
}
}
if (temperatureStage) {
if (!cmsPipelineInsertStage(pipeline.data(), cmsAT_END, temperatureStage.data())) {
qCWarning(KWIN_CORE) << "Failed to insert the color temperature pipeline stage";
}
}
if (brightnessStage) {
if (!cmsPipelineInsertStage(pipeline.data(), cmsAT_END, brightnessStage.data())) {
qCWarning(KWIN_CORE) << "Failed to insert the color brightness pipeline stage";
}
}
}
void ColorDevicePrivate::unlinkPipeline()
{
while (true) {
cmsStage *last = nullptr;
cmsPipelineUnlinkStage(pipeline.data(), cmsAT_END, &last);
if (!last) {
break;
}
}
}
static qreal interpolate(qreal a, qreal b, qreal blendFactor)
{
return (1 - blendFactor) * a + blendFactor * b;
}
void ColorDevicePrivate::updateTemperatureToneCurves()
{
temperatureStage.reset();
if (temperature == 6500) {
return;
}
// Note that cmsWhitePointFromTemp() returns a slightly green-ish white point.
const int blackBodyColorIndex = ((temperature - 1000) / 100) * 3;
const qreal blendFactor = (temperature % 100) / 100.0;
const qreal xWhitePoint = interpolate(blackbodyColor[blackBodyColorIndex + 0],
blackbodyColor[blackBodyColorIndex + 3],
blendFactor);
const qreal yWhitePoint = interpolate(blackbodyColor[blackBodyColorIndex + 1],
blackbodyColor[blackBodyColorIndex + 4],
blendFactor);
const qreal zWhitePoint = interpolate(blackbodyColor[blackBodyColorIndex + 2],
blackbodyColor[blackBodyColorIndex + 5],
blendFactor);
const double redCurveParams[] = { 1.0, xWhitePoint, 0.0 };
const double greenCurveParams[] = { 1.0, yWhitePoint, 0.0 };
const double blueCurveParams[] = { 1.0, zWhitePoint, 0.0 };
CmsScopedPointer<cmsToneCurve> redCurve(cmsBuildParametricToneCurve(nullptr, 2, redCurveParams));
if (!redCurve) {
qCWarning(KWIN_CORE) << "Failed to build the temperature tone curve for the red channel";
return;
}
CmsScopedPointer<cmsToneCurve> greenCurve(cmsBuildParametricToneCurve(nullptr, 2, greenCurveParams));
if (!greenCurve) {
qCWarning(KWIN_CORE) << "Failed to build the temperature tone curve for the green channel";
return;
}
CmsScopedPointer<cmsToneCurve> blueCurve(cmsBuildParametricToneCurve(nullptr, 2, blueCurveParams));
if (!blueCurve) {
qCWarning(KWIN_CORE) << "Failed to build the temperature tone curve for the blue channel";
return;
}
// The ownership of the tone curves will be moved to the pipeline stage.
cmsToneCurve *toneCurves[] = { redCurve.take(), greenCurve.take(), blueCurve.take() };
temperatureStage.reset(cmsStageAllocToneCurves(nullptr, 3, toneCurves));
if (!temperatureStage) {
qCWarning(KWIN_CORE) << "Failed to create the color temperature pipeline stage";
}
}
void ColorDevicePrivate::updateBrightnessToneCurves()
{
brightnessStage.reset();
if (brightness == 100) {
return;
}
const double curveParams[] = { 1.0, brightness / 100.0, 0.0 };
CmsScopedPointer<cmsToneCurve> redCurve(cmsBuildParametricToneCurve(nullptr, 2, curveParams));
if (!redCurve) {
qCWarning(KWIN_CORE) << "Failed to build the brightness tone curve for the red channel";
return;
}
CmsScopedPointer<cmsToneCurve> greenCurve(cmsBuildParametricToneCurve(nullptr, 2, curveParams));
if (!greenCurve) {
qCWarning(KWIN_CORE) << "Failed to build the brightness tone curve for the green channel";
return;
}
CmsScopedPointer<cmsToneCurve> blueCurve(cmsBuildParametricToneCurve(nullptr, 2, curveParams));
if (!blueCurve) {
qCWarning(KWIN_CORE) << "Failed to build the brightness tone curve for the blue channel";
return;
}
// The ownership of the tone curves will be moved to the pipeline stage.
cmsToneCurve *toneCurves[] = { redCurve.take(), greenCurve.take(), blueCurve.take() };
brightnessStage.reset(cmsStageAllocToneCurves(nullptr, 3, toneCurves));
if (!brightnessStage) {
qCWarning(KWIN_CORE) << "Failed to create the color brightness pipeline stage";
}
}
void ColorDevicePrivate::updateCalibrationToneCurves()
{
calibrationStage.reset();
if (profile.isNull()) {
return;
}
cmsHPROFILE handle = cmsOpenProfileFromFile(profile.toUtf8(), "r");
if (!handle) {
qCWarning(KWIN_CORE) << "Failed to open color profile file:" << profile;
return;
}
cmsToneCurve **vcgt = static_cast<cmsToneCurve **>(cmsReadTag(handle, cmsSigVcgtTag));
if (!vcgt || !vcgt[0]) {
qCWarning(KWIN_CORE) << "Profile" << profile << "has no VCGT tag";
} else {
// Need to duplicate the VCGT tone curves as they are owned by the profile.
cmsToneCurve *toneCurves[] = {
cmsDupToneCurve(vcgt[0]),
cmsDupToneCurve(vcgt[1]),
cmsDupToneCurve(vcgt[2]),
};
calibrationStage.reset(cmsStageAllocToneCurves(nullptr, 3, toneCurves));
if (!calibrationStage) {
qCWarning(KWIN_CORE) << "Failed to create the color calibration pipeline stage";
}
}
cmsCloseProfile(handle);
}
ColorDevice::ColorDevice(AbstractOutput *output, QObject *parent)
: QObject(parent)
, d(new ColorDevicePrivate)
{
d->updateTimer = new QTimer(this);
d->updateTimer->setSingleShot(true);
connect(d->updateTimer, &QTimer::timeout, this, &ColorDevice::update);
d->output = output;