kwin/plugins/nightcolor/nightcolormanager.cpp
Vlad Zahorodnii 64ad9a61d8 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.
2020-12-13 23:53:33 +02:00

912 lines
26 KiB
C++

/*
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
*/
#include "nightcolormanager.h"
#include "clockskewnotifier.h"
#include "colordevice.h"
#include "colormanager.h"
#include "nightcolordbusinterface.h"
#include "nightcolorlogging.h"
#include "nightcolorsettings.h"
#include "suncalc.h"
#include <main.h>
#include <platform.h>
#include <screens.h>
#include <workspace.h>
#include <logind.h>
#include <KGlobalAccel>
#include <KLocalizedString>
#include <QAction>
#include <QDBusConnection>
#include <QTimer>
namespace KWin {
static const int QUICK_ADJUST_DURATION = 2000;
static const int TEMPERATURE_STEP = 50;
static NightColorManager *s_instance = nullptr;
static bool checkLocation(double lat, double lng)
{
return -90 <= lat && lat <= 90 && -180 <= lng && lng <= 180;
}
NightColorManager *NightColorManager::self()
{
return s_instance;
}
NightColorManager::NightColorManager(QObject *parent)
: Plugin(parent)
{
s_instance = this;
m_iface = new NightColorDBusInterface(this);
m_skewNotifier = new ClockSkewNotifier(this);
// Display a message when Night Color is (un)inhibited.
connect(this, &NightColorManager::inhibitedChanged, this, [this] {
// TODO: Maybe use different icons?
const QString iconName = isInhibited()
? QStringLiteral("preferences-desktop-display-nightcolor-off")
: QStringLiteral("preferences-desktop-display-nightcolor-on");
const QString text = isInhibited()
? i18nc("Night Color was disabled", "Night Color Off")
: i18nc("Night Color was enabled", "Night Color On");
QDBusMessage message = QDBusMessage::createMethodCall(
QStringLiteral("org.kde.plasmashell"),
QStringLiteral("/org/kde/osdService"),
QStringLiteral("org.kde.osdService"),
QStringLiteral("showText"));
message.setArguments({ iconName, text });
QDBusConnection::sessionBus().asyncCall(message);
});
if (workspace()) {
init();
} else {
connect(kwinApp(), &Application::workspaceCreated, this, &NightColorManager::init);
}
}
NightColorManager::~NightColorManager()
{
s_instance = nullptr;
}
void NightColorManager::init()
{
NightColorSettings::instance(kwinApp()->config());
// we may always read in the current config
readConfig();
if (!isAvailable()) {
return;
}
// legacy shortcut with localized key (to avoid breaking existing config)
if (i18n("Toggle Night Color") != QStringLiteral("Toggle Night Color")) {
QAction toggleActionLegacy;
toggleActionLegacy.setProperty("componentName", QStringLiteral(KWIN_NAME));
toggleActionLegacy.setObjectName(i18n("Toggle Night Color"));
KGlobalAccel::self()->removeAllShortcuts(&toggleActionLegacy);
}
QAction *toggleAction = new QAction(this);
toggleAction->setProperty("componentName", QStringLiteral(KWIN_NAME));
toggleAction->setObjectName(QStringLiteral("Toggle Night Color"));
toggleAction->setText(i18n("Toggle Night Color"));
KGlobalAccel::setGlobalShortcut(toggleAction, QList<QKeySequence>());
input()->registerShortcut(QKeySequence(), toggleAction, this, &NightColorManager::toggle);
connect(Screens::self(), &Screens::countChanged, this, &NightColorManager::hardReset);
connect(LogindIntegration::self(), &LogindIntegration::sessionActiveChanged, this,
[this](bool active) {
if (active) {
hardReset();
} else {
cancelAllTimers();
}
}
);
connect(m_skewNotifier, &ClockSkewNotifier::clockSkewed, this, [this]() {
// check if we're resuming from suspend - in this case do a hard reset
// Note: We're using the time clock to detect a suspend phase instead of connecting to the
// provided logind dbus signal, because this signal would be received way too late.
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.DBus.Properties",
QStringLiteral("Get"));
message.setArguments(QVariantList({"org.freedesktop.login1.Manager", QStringLiteral("PreparingForSleep")}));
QDBusReply<QVariant> reply = QDBusConnection::systemBus().call(message);
bool comingFromSuspend;
if (reply.isValid()) {
comingFromSuspend = reply.value().toBool();
} else {
qCDebug(KWIN_NIGHTCOLOR) << "Failed to get PreparingForSleep Property of logind session:" << reply.error().message();
// Always do a hard reset in case we have no further information.
comingFromSuspend = true;
}
if (comingFromSuspend) {
hardReset();
} else {
resetAllTimers();
}
});
hardReset();
}
void NightColorManager::hardReset()
{
cancelAllTimers();
updateTransitionTimings(true);
updateTargetTemperature();
if (isAvailable() && isEnabled() && !isInhibited()) {
setRunning(true);
commitGammaRamps(currentTargetTemp());
}
resetAllTimers();
}
void NightColorManager::reparseConfigAndReset()
{
cancelAllTimers();
readConfig();
hardReset();
}
void NightColorManager::toggle()
{
m_isGloballyInhibited = !m_isGloballyInhibited;
m_isGloballyInhibited ? inhibit() : uninhibit();
}
bool NightColorManager::isInhibited() const
{
return m_inhibitReferenceCount;
}
void NightColorManager::inhibit()
{
m_inhibitReferenceCount++;
if (m_inhibitReferenceCount == 1) {
resetAllTimers();
emit inhibitedChanged();
}
}
void NightColorManager::uninhibit()
{
m_inhibitReferenceCount--;
if (!m_inhibitReferenceCount) {
resetAllTimers();
emit inhibitedChanged();
}
}
bool NightColorManager::isEnabled() const
{
return m_active;
}
bool NightColorManager::isRunning() const
{
return m_running;
}
bool NightColorManager::isAvailable() const
{
return kwinApp()->platform()->supportsGammaControl();
}
int NightColorManager::currentTemperature() const
{
return m_currentTemp;
}
int NightColorManager::targetTemperature() const
{
return m_targetTemperature;
}
NightColorMode NightColorManager::mode() const
{
return m_mode;
}
QDateTime NightColorManager::previousTransitionDateTime() const
{
return m_prev.first;
}
qint64 NightColorManager::previousTransitionDuration() const
{
return m_prev.first.msecsTo(m_prev.second);
}
QDateTime NightColorManager::scheduledTransitionDateTime() const
{
return m_next.first;
}
qint64 NightColorManager::scheduledTransitionDuration() const
{
return m_next.first.msecsTo(m_next.second);
}
void NightColorManager::readConfig()
{
NightColorSettings *s = NightColorSettings::self();
s->load();
setEnabled(s->active());
const NightColorMode mode = s->mode();
switch (s->mode()) {
case NightColorMode::Automatic:
case NightColorMode::Location:
case NightColorMode::Timings:
case NightColorMode::Constant:
setMode(mode);
break;
default:
// Fallback for invalid setting values.
setMode(NightColorMode::Automatic);
break;
}
m_nightTargetTemp = qBound(MIN_TEMPERATURE, s->nightTemperature(), NEUTRAL_TEMPERATURE);
double lat, lng;
auto correctReadin = [&lat, &lng]() {
if (!checkLocation(lat, lng)) {
// out of domain
lat = 0;
lng = 0;
}
};
// automatic
lat = s->latitudeAuto();
lng = s->longitudeAuto();
correctReadin();
m_latAuto = lat;
m_lngAuto = lng;
// fixed location
lat = s->latitudeFixed();
lng = s->longitudeFixed();
correctReadin();
m_latFixed = lat;
m_lngFixed = lng;
// fixed timings
QTime mrB = QTime::fromString(s->morningBeginFixed(), "hhmm");
QTime evB = QTime::fromString(s->eveningBeginFixed(), "hhmm");
int diffME = mrB.msecsTo(evB);
if (diffME <= 0) {
// morning not strictly before evening - use defaults
mrB = QTime(6,0);
evB = QTime(18,0);
diffME = mrB.msecsTo(evB);
}
int diffMin = qMin(diffME, MSC_DAY - diffME);
int trTime = s->transitionTime() * 1000 * 60;
if (trTime < 0 || diffMin <= trTime) {
// transition time too long - use defaults
mrB = QTime(6,0);
evB = QTime(18,0);
trTime = FALLBACK_SLOW_UPDATE_TIME;
}
m_morning = mrB;
m_evening = evB;
m_trTime = qMax(trTime / 1000 / 60, 1);
}
void NightColorManager::resetAllTimers()
{
cancelAllTimers();
if (isAvailable()) {
setRunning(isEnabled() && !isInhibited());
// we do this also for active being false in order to reset the temperature back to the day value
resetQuickAdjustTimer();
} else {
setRunning(false);
}
}
void NightColorManager::cancelAllTimers()
{
delete m_slowUpdateStartTimer;
delete m_slowUpdateTimer;
delete m_quickAdjustTimer;
m_slowUpdateStartTimer = nullptr;
m_slowUpdateTimer = nullptr;
m_quickAdjustTimer = nullptr;
}
void NightColorManager::resetQuickAdjustTimer()
{
updateTransitionTimings(false);
updateTargetTemperature();
int tempDiff = qAbs(currentTargetTemp() - m_currentTemp);
// allow tolerance of one TEMPERATURE_STEP to compensate if a slow update is coincidental
if (tempDiff > TEMPERATURE_STEP) {
cancelAllTimers();
m_quickAdjustTimer = new QTimer(this);
m_quickAdjustTimer->setSingleShot(false);
connect(m_quickAdjustTimer, &QTimer::timeout, this, &NightColorManager::quickAdjust);
int interval = QUICK_ADJUST_DURATION / (tempDiff / TEMPERATURE_STEP);
if (interval == 0) {
interval = 1;
}
m_quickAdjustTimer->start(interval);
} else {
resetSlowUpdateStartTimer();
}
}
void NightColorManager::quickAdjust()
{
if (!m_quickAdjustTimer) {
return;
}
int nextTemp;
const int targetTemp = currentTargetTemp();
if (m_currentTemp < targetTemp) {
nextTemp = qMin(m_currentTemp + TEMPERATURE_STEP, targetTemp);
} else {
nextTemp = qMax(m_currentTemp - TEMPERATURE_STEP, targetTemp);
}
commitGammaRamps(nextTemp);
if (nextTemp == targetTemp) {
// stop timer, we reached the target temp
delete m_quickAdjustTimer;
m_quickAdjustTimer = nullptr;
resetSlowUpdateStartTimer();
}
}
void NightColorManager::resetSlowUpdateStartTimer()
{
delete m_slowUpdateStartTimer;
m_slowUpdateStartTimer = nullptr;
if (!m_running || m_quickAdjustTimer) {
// only reenable the slow update start timer when quick adjust is not active anymore
return;
}
// There is no need for starting the slow update timer. Screen color temperature
// will be constant all the time now.
if (m_mode == NightColorMode::Constant) {
return;
}
// set up the next slow update
m_slowUpdateStartTimer = new QTimer(this);
m_slowUpdateStartTimer->setSingleShot(true);
connect(m_slowUpdateStartTimer, &QTimer::timeout, this, &NightColorManager::resetSlowUpdateStartTimer);
updateTransitionTimings(false);
updateTargetTemperature();
const int diff = QDateTime::currentDateTime().msecsTo(m_next.first);
if (diff <= 0) {
qCCritical(KWIN_NIGHTCOLOR) << "Error in time calculation. Deactivating Night Color.";
return;
}
m_slowUpdateStartTimer->start(diff);
// start the current slow update
resetSlowUpdateTimer();
}
void NightColorManager::resetSlowUpdateTimer()
{
delete m_slowUpdateTimer;
m_slowUpdateTimer = nullptr;
const QDateTime now = QDateTime::currentDateTime();
const bool isDay = daylight();
const int targetTemp = isDay ? m_dayTargetTemp : m_nightTargetTemp;
// We've reached the target color temperature or the transition time is zero.
if (m_prev.first == m_prev.second || m_currentTemp == targetTemp) {
commitGammaRamps(targetTemp);
return;
}
if (m_prev.first <= now && now <= m_prev.second) {
int availTime = now.msecsTo(m_prev.second);
m_slowUpdateTimer = new QTimer(this);
m_slowUpdateTimer->setSingleShot(false);
if (isDay) {
connect(m_slowUpdateTimer, &QTimer::timeout, this, [this]() {slowUpdate(m_dayTargetTemp);});
} else {
connect(m_slowUpdateTimer, &QTimer::timeout, this, [this]() {slowUpdate(m_nightTargetTemp);});
}
// calculate interval such as temperature is changed by TEMPERATURE_STEP K per timer timeout
int interval = availTime * TEMPERATURE_STEP / qAbs(targetTemp - m_currentTemp);
if (interval == 0) {
interval = 1;
}
m_slowUpdateTimer->start(interval);
}
}
void NightColorManager::slowUpdate(int targetTemp)
{
if (!m_slowUpdateTimer) {
return;
}
int nextTemp;
if (m_currentTemp < targetTemp) {
nextTemp = qMin(m_currentTemp + TEMPERATURE_STEP, targetTemp);
} else {
nextTemp = qMax(m_currentTemp - TEMPERATURE_STEP, targetTemp);
}
commitGammaRamps(nextTemp);
if (nextTemp == targetTemp) {
// stop timer, we reached the target temp
delete m_slowUpdateTimer;
m_slowUpdateTimer = nullptr;
}
}
void NightColorManager::updateTargetTemperature()
{
const int targetTemperature = mode() != NightColorMode::Constant && daylight() ? m_dayTargetTemp : m_nightTargetTemp;
if (m_targetTemperature == targetTemperature) {
return;
}
m_targetTemperature = targetTemperature;
emit targetTemperatureChanged();
}
void NightColorManager::updateTransitionTimings(bool force)
{
if (m_mode == NightColorMode::Constant) {
m_next = DateTimes();
m_prev = DateTimes();
emit previousTransitionTimingsChanged();
emit scheduledTransitionTimingsChanged();
return;
}
const QDateTime todayNow = QDateTime::currentDateTime();
if (m_mode == NightColorMode::Timings) {
const QDateTime morB = QDateTime(todayNow.date(), m_morning);
const QDateTime morE = morB.addSecs(m_trTime * 60);
const QDateTime eveB = QDateTime(todayNow.date(), m_evening);
const QDateTime eveE = eveB.addSecs(m_trTime * 60);
if (morB <= todayNow && todayNow < eveB) {
m_next = DateTimes(eveB, eveE);
m_prev = DateTimes(morB, morE);
} else if (todayNow < morB) {
m_next = DateTimes(morB, morE);
m_prev = DateTimes(eveB.addDays(-1), eveE.addDays(-1));
} else {
m_next = DateTimes(morB.addDays(1), morE.addDays(1));
m_prev = DateTimes(eveB, eveE);
}
emit previousTransitionTimingsChanged();
emit scheduledTransitionTimingsChanged();
return;
}
double lat, lng;
if (m_mode == NightColorMode::Automatic) {
lat = m_latAuto;
lng = m_lngAuto;
} else {
lat = m_latFixed;
lng = m_lngFixed;
}
if (!force) {
// first try by only switching the timings
if (daylight()) {
// next is morning
m_prev = m_next;
m_next = getSunTimings(todayNow.addDays(1), lat, lng, true);
} else {
// next is evening
m_prev = m_next;
m_next = getSunTimings(todayNow, lat, lng, false);
}
}
if (force || !checkAutomaticSunTimings()) {
// in case this fails, reset them
DateTimes morning = getSunTimings(todayNow, lat, lng, true);
if (todayNow < morning.first) {
m_prev = getSunTimings(todayNow.addDays(-1), lat, lng, false);
m_next = morning;
} else {
DateTimes evening = getSunTimings(todayNow, lat, lng, false);
if (todayNow < evening.first) {
m_prev = morning;
m_next = evening;
} else {
m_prev = evening;
m_next = getSunTimings(todayNow.addDays(1), lat, lng, true);
}
}
}
emit previousTransitionTimingsChanged();
emit scheduledTransitionTimingsChanged();
}
DateTimes NightColorManager::getSunTimings(const QDateTime &dateTime, double latitude, double longitude, bool morning) const
{
DateTimes dateTimes = calculateSunTimings(dateTime, latitude, longitude, morning);
// At locations near the poles it is possible, that we can't
// calculate some or all sun timings (midnight sun).
// In this case try to fallback to sensible default values.
const bool beginDefined = !dateTimes.first.isNull();
const bool endDefined = !dateTimes.second.isNull();
if (!beginDefined || !endDefined) {
if (beginDefined) {
dateTimes.second = dateTimes.first.addMSecs( FALLBACK_SLOW_UPDATE_TIME );
} else if (endDefined) {
dateTimes.first = dateTimes.second.addMSecs( - FALLBACK_SLOW_UPDATE_TIME );
} else {
// Just use default values for morning and evening, but the user
// will probably deactivate Night Color anyway if he is living
// in a region without clear sun rise and set.
const QTime referenceTime = morning ? QTime(6, 0) : QTime(18, 0);
dateTimes.first = QDateTime(dateTime.date(), referenceTime);
dateTimes.second = dateTimes.first.addMSecs( FALLBACK_SLOW_UPDATE_TIME );
}
}
return dateTimes;
}
bool NightColorManager::checkAutomaticSunTimings() const
{
if (m_prev.first.isValid() && m_prev.second.isValid() &&
m_next.first.isValid() && m_next.second.isValid()) {
const QDateTime todayNow = QDateTime::currentDateTime();
return m_prev.first <= todayNow && todayNow < m_next.first &&
m_prev.first.msecsTo(m_next.first) < MSC_DAY * 23./24;
}
return false;
}
bool NightColorManager::daylight() const
{
return m_prev.first.date() == m_next.first.date();
}
int NightColorManager::currentTargetTemp() const
{
if (!m_running) {
return NEUTRAL_TEMPERATURE;
}
if (m_mode == NightColorMode::Constant) {
return m_nightTargetTemp;
}
const QDateTime todayNow = QDateTime::currentDateTime();
auto f = [this, todayNow](int target1, int target2) {
if (todayNow <= m_prev.second) {
double residueQuota = todayNow.msecsTo(m_prev.second) / (double)m_prev.first.msecsTo(m_prev.second);
double ret = (int)((1. - residueQuota) * (double)target2 + residueQuota * (double)target1);
// remove single digits
ret = ((int)(0.1 * ret)) * 10;
return (int)ret;
} else {
return target2;
}
};
if (daylight()) {
return f(m_nightTargetTemp, m_dayTargetTemp);
} else {
return f(m_dayTargetTemp, m_nightTargetTemp);
}
}
void NightColorManager::commitGammaRamps(int temperature)
{
const QVector<ColorDevice *> devices = ColorManager::self()->devices();
for (ColorDevice *device : devices) {
device->setTemperature(temperature);
}
setCurrentTemperature(temperature);
}
QHash<QString, QVariant> NightColorManager::info() const
{
return QHash<QString, QVariant> {
{ QStringLiteral("Available"), isAvailable() },
{ QStringLiteral("ActiveEnabled"), true},
{ QStringLiteral("Active"), m_active},
{ QStringLiteral("ModeEnabled"), true},
{ QStringLiteral("Mode"), (int)m_mode},
{ QStringLiteral("NightTemperatureEnabled"), true},
{ QStringLiteral("NightTemperature"), m_nightTargetTemp},
{ QStringLiteral("Running"), m_running},
{ QStringLiteral("CurrentColorTemperature"), m_currentTemp},
{ QStringLiteral("LatitudeAuto"), m_latAuto},
{ QStringLiteral("LongitudeAuto"), m_lngAuto},
{ QStringLiteral("LocationEnabled"), true},
{ QStringLiteral("LatitudeFixed"), m_latFixed},
{ QStringLiteral("LongitudeFixed"), m_lngFixed},
{ QStringLiteral("TimingsEnabled"), true},
{ QStringLiteral("MorningBeginFixed"), m_morning.toString(Qt::ISODate)},
{ QStringLiteral("EveningBeginFixed"), m_evening.toString(Qt::ISODate)},
{ QStringLiteral("TransitionTime"), m_trTime},
};
}
bool NightColorManager::changeConfiguration(QHash<QString, QVariant> data)
{
bool activeUpdate, modeUpdate, tempUpdate, locUpdate, timeUpdate;
activeUpdate = modeUpdate = tempUpdate = locUpdate = timeUpdate = false;
bool active = m_active;
NightColorMode mode = m_mode;
int nightT = m_nightTargetTemp;
double lat = m_latFixed;
double lng = m_lngFixed;
QTime mor = m_morning;
QTime eve = m_evening;
int trT = m_trTime;
QHash<QString, QVariant>::const_iterator iter1, iter2, iter3;
iter1 = data.constFind("Active");
if (iter1 != data.constEnd()) {
if (!iter1.value().canConvert<bool>()) {
return false;
}
bool act = iter1.value().toBool();
activeUpdate = m_active != act;
active = act;
}
iter1 = data.constFind("Mode");
if (iter1 != data.constEnd()) {
if (!iter1.value().canConvert<int>()) {
return false;
}
int mo = iter1.value().toInt();
if (mo < 0 || 3 < mo) {
return false;
}
NightColorMode moM;
switch (mo) {
case 0:
moM = NightColorMode::Automatic;
break;
case 1:
moM = NightColorMode::Location;
break;
case 2:
moM = NightColorMode::Timings;
break;
case 3:
moM = NightColorMode::Constant;
break;
}
modeUpdate = m_mode != moM;
mode = moM;
}
iter1 = data.constFind("NightTemperature");
if (iter1 != data.constEnd()) {
if (!iter1.value().canConvert<int>()) {
return false;
}
int nT = iter1.value().toInt();
if (nT < MIN_TEMPERATURE || NEUTRAL_TEMPERATURE < nT) {
return false;
}
tempUpdate = m_nightTargetTemp != nT;
nightT = nT;
}
iter1 = data.constFind("LatitudeFixed");
iter2 = data.constFind("LongitudeFixed");
if (iter1 != data.constEnd() && iter2 != data.constEnd()) {
if (!iter1.value().canConvert<double>() || !iter2.value().canConvert<double>()) {
return false;
}
double la = iter1.value().toDouble();
double ln = iter2.value().toDouble();
if (!checkLocation(la, ln)) {
return false;
}
locUpdate = m_latFixed != la || m_lngFixed != ln;
lat = la;
lng = ln;
}
iter1 = data.constFind("MorningBeginFixed");
iter2 = data.constFind("EveningBeginFixed");
iter3 = data.constFind("TransitionTime");
if (iter1 != data.constEnd() && iter2 != data.constEnd() && iter3 != data.constEnd()) {
if (!iter1.value().canConvert<QString>() || !iter2.value().canConvert<QString>() || !iter3.value().canConvert<int>()) {
return false;
}
QTime mo = QTime::fromString(iter1.value().toString(), Qt::ISODate);
QTime ev = QTime::fromString(iter2.value().toString(), Qt::ISODate);
if (!mo.isValid() || !ev.isValid()) {
return false;
}
int tT = iter3.value().toInt();
int diffME = mo.msecsTo(ev);
if (diffME <= 0 || qMin(diffME, MSC_DAY - diffME) <= tT * 60 * 1000 || tT < 1) {
// morning not strictly before evening, transition time too long or transition time out of bounds
return false;
}
timeUpdate = m_morning != mo || m_evening != ev || m_trTime != tT;
mor = mo;
eve = ev;
trT = tT;
}
if (!(activeUpdate || modeUpdate || tempUpdate || locUpdate || timeUpdate)) {
return true;
}
bool resetNeeded = activeUpdate || modeUpdate || tempUpdate ||
(locUpdate && mode == NightColorMode::Location) ||
(timeUpdate && mode == NightColorMode::Timings);
if (resetNeeded) {
cancelAllTimers();
}
NightColorSettings *s = NightColorSettings::self();
if (activeUpdate) {
setEnabled(active);
s->setActive(active);
}
if (modeUpdate) {
setMode(mode);
s->setMode(mode);
}
if (tempUpdate) {
m_nightTargetTemp = nightT;
s->setNightTemperature(nightT);
}
if (locUpdate) {
m_latFixed = lat;
m_lngFixed = lng;
s->setLatitudeFixed(lat);
s->setLongitudeFixed(lng);
}
if (timeUpdate) {
m_morning = mor;
m_evening = eve;
m_trTime = trT;
s->setMorningBeginFixed(mor.toString("hhmm"));
s->setEveningBeginFixed(eve.toString("hhmm"));
s->setTransitionTime(trT);
}
s->save();
if (resetNeeded) {
resetAllTimers();
}
emit configChange(info());
return true;
}
void NightColorManager::autoLocationUpdate(double latitude, double longitude)
{
qCDebug(KWIN_NIGHTCOLOR, "Received new location (lat: %f, lng: %f)", latitude, longitude);
if (!checkLocation(latitude, longitude)) {
return;
}
// we tolerate small deviations with minimal impact on sun timings
if (qAbs(m_latAuto - latitude) < 2 && qAbs(m_lngAuto - longitude) < 1) {
return;
}
cancelAllTimers();
m_latAuto = latitude;
m_lngAuto = longitude;
NightColorSettings *s = NightColorSettings::self();
s->setLatitudeAuto(latitude);
s->setLongitudeAuto(longitude);
s->save();
resetAllTimers();
emit configChange(info());
}
void NightColorManager::setEnabled(bool enabled)
{
if (m_active == enabled) {
return;
}
m_active = enabled;
m_skewNotifier->setActive(enabled);
emit enabledChanged();
}
void NightColorManager::setRunning(bool running)
{
if (m_running == running) {
return;
}
m_running = running;
emit runningChanged();
}
void NightColorManager::setCurrentTemperature(int temperature)
{
if (m_currentTemp == temperature) {
return;
}
m_currentTemp = temperature;
emit currentTemperatureChanged();
}
void NightColorManager::setMode(NightColorMode mode)
{
if (m_mode == mode) {
return;
}
m_mode = mode;
emit modeChanged();
}
} // namespace KWin