File indexing completed on 2024-11-10 04:57:04
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2017 Roman Gilg <subdiff@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "nightcolormanager.h" 0010 #include "clockskewnotifier.h" 0011 #include "colors/colordevice.h" 0012 #include "colors/colormanager.h" 0013 #include "nightcolordbusinterface.h" 0014 #include "nightcolorlogging.h" 0015 #include "nightcolorsettings.h" 0016 #include "suncalc.h" 0017 0018 #include <core/outputbackend.h> 0019 #include <core/session.h> 0020 #include <input.h> 0021 #include <main.h> 0022 #include <workspace.h> 0023 0024 #include <KGlobalAccel> 0025 #include <KLocalizedString> 0026 0027 #include <QAction> 0028 #include <QDBusConnection> 0029 #include <QDBusMessage> 0030 #include <QDBusPendingReply> 0031 #include <QDBusReply> 0032 #include <QTimer> 0033 0034 namespace KWin 0035 { 0036 0037 static const int QUICK_ADJUST_DURATION = 2000; 0038 static const int TEMPERATURE_STEP = 50; 0039 static NightColorManager *s_instance = nullptr; 0040 0041 static bool checkLocation(double lat, double lng) 0042 { 0043 return -90 <= lat && lat <= 90 && -180 <= lng && lng <= 180; 0044 } 0045 0046 NightColorManager *NightColorManager::self() 0047 { 0048 return s_instance; 0049 } 0050 0051 NightColorManager::NightColorManager() 0052 { 0053 NightColorSettings::instance(kwinApp()->config()); 0054 s_instance = this; 0055 0056 m_iface = new NightColorDBusInterface(this); 0057 m_skewNotifier = new ClockSkewNotifier(this); 0058 0059 // Display a message when Night Color is (un)inhibited. 0060 connect(this, &NightColorManager::inhibitedChanged, this, [this] { 0061 const QString iconName = isInhibited() 0062 ? QStringLiteral("redshift-status-off") 0063 : m_daylight && m_targetTemperature != DEFAULT_DAY_TEMPERATURE ? QStringLiteral("redshift-status-day") 0064 : QStringLiteral("redshift-status-on"); 0065 0066 const QString text = isInhibited() 0067 ? i18nc("Night Light was disabled", "Night Light Off") 0068 : i18nc("Night Light was enabled", "Night Light On"); 0069 0070 QDBusMessage message = QDBusMessage::createMethodCall( 0071 QStringLiteral("org.kde.plasmashell"), 0072 QStringLiteral("/org/kde/osdService"), 0073 QStringLiteral("org.kde.osdService"), 0074 QStringLiteral("showText")); 0075 message.setArguments({iconName, text}); 0076 0077 QDBusConnection::sessionBus().asyncCall(message); 0078 }); 0079 0080 m_configWatcher = KConfigWatcher::create(kwinApp()->config()); 0081 connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, &NightColorManager::reconfigure); 0082 0083 // we may always read in the current config 0084 readConfig(); 0085 0086 QAction *toggleAction = new QAction(this); 0087 toggleAction->setProperty("componentName", QStringLiteral("kwin")); 0088 toggleAction->setObjectName(QStringLiteral("Toggle Night Color")); 0089 toggleAction->setText(i18n("Toggle Night Light")); 0090 KGlobalAccel::setGlobalShortcut(toggleAction, QList<QKeySequence>()); 0091 connect(toggleAction, &QAction::triggered, this, &NightColorManager::toggle); 0092 0093 connect(kwinApp()->colorManager(), &ColorManager::deviceAdded, this, &NightColorManager::hardReset); 0094 0095 connect(kwinApp()->session(), &Session::activeChanged, this, [this](bool active) { 0096 if (active) { 0097 hardReset(); 0098 } else { 0099 cancelAllTimers(); 0100 } 0101 }); 0102 0103 connect(m_skewNotifier, &ClockSkewNotifier::clockSkewed, this, [this]() { 0104 // check if we're resuming from suspend - in this case do a hard reset 0105 // Note: We're using the time clock to detect a suspend phase instead of connecting to the 0106 // provided logind dbus signal, because this signal would be received way too late. 0107 QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", 0108 "/org/freedesktop/login1", 0109 "org.freedesktop.DBus.Properties", 0110 QStringLiteral("Get")); 0111 message.setArguments(QVariantList({"org.freedesktop.login1.Manager", QStringLiteral("PreparingForSleep")})); 0112 QDBusReply<QVariant> reply = QDBusConnection::systemBus().call(message); 0113 bool comingFromSuspend; 0114 if (reply.isValid()) { 0115 comingFromSuspend = reply.value().toBool(); 0116 } else { 0117 qCDebug(KWIN_NIGHTCOLOR) << "Failed to get PreparingForSleep Property of logind session:" << reply.error().message(); 0118 // Always do a hard reset in case we have no further information. 0119 comingFromSuspend = true; 0120 } 0121 0122 if (comingFromSuspend) { 0123 hardReset(); 0124 } else { 0125 resetAllTimers(); 0126 } 0127 }); 0128 0129 hardReset(); 0130 } 0131 0132 NightColorManager::~NightColorManager() 0133 { 0134 s_instance = nullptr; 0135 } 0136 0137 void NightColorManager::hardReset() 0138 { 0139 cancelAllTimers(); 0140 0141 updateTransitionTimings(true); 0142 updateTargetTemperature(); 0143 0144 if (isEnabled() && !isInhibited()) { 0145 setRunning(true); 0146 commitGammaRamps(currentTargetTemp()); 0147 } 0148 resetAllTimers(); 0149 } 0150 0151 void NightColorManager::reconfigure() 0152 { 0153 cancelAllTimers(); 0154 readConfig(); 0155 resetAllTimers(); 0156 } 0157 0158 void NightColorManager::toggle() 0159 { 0160 m_isGloballyInhibited = !m_isGloballyInhibited; 0161 m_isGloballyInhibited ? inhibit() : uninhibit(); 0162 } 0163 0164 bool NightColorManager::isInhibited() const 0165 { 0166 return m_inhibitReferenceCount; 0167 } 0168 0169 void NightColorManager::inhibit() 0170 { 0171 m_inhibitReferenceCount++; 0172 0173 if (m_inhibitReferenceCount == 1) { 0174 resetAllTimers(); 0175 Q_EMIT inhibitedChanged(); 0176 } 0177 } 0178 0179 void NightColorManager::uninhibit() 0180 { 0181 m_inhibitReferenceCount--; 0182 0183 if (!m_inhibitReferenceCount) { 0184 resetAllTimers(); 0185 Q_EMIT inhibitedChanged(); 0186 } 0187 } 0188 0189 bool NightColorManager::isEnabled() const 0190 { 0191 return m_active; 0192 } 0193 0194 bool NightColorManager::isRunning() const 0195 { 0196 return m_running; 0197 } 0198 0199 int NightColorManager::currentTemperature() const 0200 { 0201 return m_currentTemp; 0202 } 0203 0204 int NightColorManager::targetTemperature() const 0205 { 0206 return m_targetTemperature; 0207 } 0208 0209 NightColorMode NightColorManager::mode() const 0210 { 0211 return m_mode; 0212 } 0213 0214 QDateTime NightColorManager::previousTransitionDateTime() const 0215 { 0216 return m_prev.first; 0217 } 0218 0219 qint64 NightColorManager::previousTransitionDuration() const 0220 { 0221 return m_prev.first.msecsTo(m_prev.second); 0222 } 0223 0224 QDateTime NightColorManager::scheduledTransitionDateTime() const 0225 { 0226 return m_next.first; 0227 } 0228 0229 qint64 NightColorManager::scheduledTransitionDuration() const 0230 { 0231 return m_next.first.msecsTo(m_next.second); 0232 } 0233 0234 void NightColorManager::readConfig() 0235 { 0236 NightColorSettings *s = NightColorSettings::self(); 0237 s->load(); 0238 0239 setEnabled(s->active()); 0240 0241 const NightColorMode mode = s->mode(); 0242 switch (s->mode()) { 0243 case NightColorMode::Automatic: 0244 case NightColorMode::Location: 0245 case NightColorMode::Timings: 0246 case NightColorMode::Constant: 0247 setMode(mode); 0248 break; 0249 default: 0250 // Fallback for invalid setting values. 0251 setMode(NightColorMode::Automatic); 0252 break; 0253 } 0254 0255 m_dayTargetTemp = std::clamp(s->dayTemperature(), MIN_TEMPERATURE, DEFAULT_DAY_TEMPERATURE); 0256 m_nightTargetTemp = std::clamp(s->nightTemperature(), MIN_TEMPERATURE, DEFAULT_DAY_TEMPERATURE); 0257 0258 double lat, lng; 0259 auto correctReadin = [&lat, &lng]() { 0260 if (!checkLocation(lat, lng)) { 0261 // out of domain 0262 lat = 0; 0263 lng = 0; 0264 } 0265 }; 0266 // automatic 0267 lat = s->latitudeAuto(); 0268 lng = s->longitudeAuto(); 0269 correctReadin(); 0270 m_latAuto = lat; 0271 m_lngAuto = lng; 0272 // fixed location 0273 lat = s->latitudeFixed(); 0274 lng = s->longitudeFixed(); 0275 correctReadin(); 0276 m_latFixed = lat; 0277 m_lngFixed = lng; 0278 0279 // fixed timings 0280 QTime mrB = QTime::fromString(s->morningBeginFixed(), "hhmm"); 0281 QTime evB = QTime::fromString(s->eveningBeginFixed(), "hhmm"); 0282 0283 int diffME = evB > mrB ? mrB.msecsTo(evB) : evB.msecsTo(mrB); 0284 int diffMin = std::min(diffME, MSC_DAY - diffME); 0285 0286 int trTime = s->transitionTime() * 1000 * 60; 0287 if (trTime < 0 || diffMin <= trTime) { 0288 // transition time too long - use defaults 0289 mrB = QTime(6, 0); 0290 evB = QTime(18, 0); 0291 trTime = FALLBACK_SLOW_UPDATE_TIME; 0292 } 0293 m_morning = mrB; 0294 m_evening = evB; 0295 m_trTime = std::max(trTime / 1000 / 60, 1); 0296 } 0297 0298 void NightColorManager::resetAllTimers() 0299 { 0300 cancelAllTimers(); 0301 setRunning(isEnabled() && !isInhibited()); 0302 // we do this also for active being false in order to reset the temperature back to the day value 0303 updateTransitionTimings(false); 0304 updateTargetTemperature(); 0305 resetQuickAdjustTimer(currentTargetTemp()); 0306 } 0307 0308 void NightColorManager::cancelAllTimers() 0309 { 0310 m_slowUpdateStartTimer.reset(); 0311 m_slowUpdateTimer.reset(); 0312 m_quickAdjustTimer.reset(); 0313 } 0314 0315 void NightColorManager::resetQuickAdjustTimer(int targetTemp) 0316 { 0317 int tempDiff = std::abs(targetTemp - m_currentTemp); 0318 // allow tolerance of one TEMPERATURE_STEP to compensate if a slow update is coincidental 0319 if (tempDiff > TEMPERATURE_STEP) { 0320 cancelAllTimers(); 0321 m_quickAdjustTimer = std::make_unique<QTimer>(); 0322 m_quickAdjustTimer->setSingleShot(false); 0323 connect(m_quickAdjustTimer.get(), &QTimer::timeout, this, [this, targetTemp]() { 0324 quickAdjust(targetTemp); 0325 }); 0326 0327 int interval = (QUICK_ADJUST_DURATION / (m_previewTimer && m_previewTimer->isActive() ? 8 : 1)) / (tempDiff / TEMPERATURE_STEP); 0328 if (interval == 0) { 0329 interval = 1; 0330 } 0331 m_quickAdjustTimer->start(interval); 0332 } else { 0333 resetSlowUpdateStartTimer(); 0334 } 0335 } 0336 0337 void NightColorManager::quickAdjust(int targetTemp) 0338 { 0339 if (!m_quickAdjustTimer) { 0340 return; 0341 } 0342 0343 int nextTemp; 0344 0345 if (m_currentTemp < targetTemp) { 0346 nextTemp = std::min(m_currentTemp + TEMPERATURE_STEP, targetTemp); 0347 } else { 0348 nextTemp = std::max(m_currentTemp - TEMPERATURE_STEP, targetTemp); 0349 } 0350 commitGammaRamps(nextTemp); 0351 0352 if (nextTemp == targetTemp) { 0353 // stop timer, we reached the target temp 0354 m_quickAdjustTimer.reset(); 0355 resetSlowUpdateStartTimer(); 0356 } 0357 } 0358 0359 void NightColorManager::resetSlowUpdateStartTimer() 0360 { 0361 m_slowUpdateStartTimer.reset(); 0362 0363 if (!m_running || m_quickAdjustTimer) { 0364 // only reenable the slow update start timer when quick adjust is not active anymore 0365 return; 0366 } 0367 0368 // There is no need for starting the slow update timer. Screen color temperature 0369 // will be constant all the time now. 0370 if (m_mode == NightColorMode::Constant) { 0371 return; 0372 } 0373 0374 // set up the next slow update 0375 m_slowUpdateStartTimer = std::make_unique<QTimer>(); 0376 m_slowUpdateStartTimer->setSingleShot(true); 0377 connect(m_slowUpdateStartTimer.get(), &QTimer::timeout, this, &NightColorManager::resetSlowUpdateStartTimer); 0378 0379 updateTransitionTimings(false); 0380 updateTargetTemperature(); 0381 0382 const int diff = QDateTime::currentDateTime().msecsTo(m_next.first); 0383 if (diff <= 0) { 0384 qCCritical(KWIN_NIGHTCOLOR) << "Error in time calculation. Deactivating Night Color."; 0385 return; 0386 } 0387 m_slowUpdateStartTimer->start(diff); 0388 0389 // start the current slow update 0390 resetSlowUpdateTimer(); 0391 } 0392 0393 void NightColorManager::resetSlowUpdateTimer() 0394 { 0395 m_slowUpdateTimer.reset(); 0396 0397 const QDateTime now = QDateTime::currentDateTime(); 0398 const bool isDay = daylight(); 0399 const int targetTemp = isDay ? m_dayTargetTemp : m_nightTargetTemp; 0400 0401 // We've reached the target color temperature or the transition time is zero. 0402 if (m_prev.first == m_prev.second || m_currentTemp == targetTemp) { 0403 commitGammaRamps(targetTemp); 0404 return; 0405 } 0406 0407 if (m_prev.first <= now && now <= m_prev.second) { 0408 int availTime = now.msecsTo(m_prev.second); 0409 m_slowUpdateTimer = std::make_unique<QTimer>(); 0410 m_slowUpdateTimer->setSingleShot(false); 0411 if (isDay) { 0412 connect(m_slowUpdateTimer.get(), &QTimer::timeout, this, [this]() { 0413 slowUpdate(m_dayTargetTemp); 0414 }); 0415 } else { 0416 connect(m_slowUpdateTimer.get(), &QTimer::timeout, this, [this]() { 0417 slowUpdate(m_nightTargetTemp); 0418 }); 0419 } 0420 0421 // calculate interval such as temperature is changed by TEMPERATURE_STEP K per timer timeout 0422 int interval = availTime * TEMPERATURE_STEP / std::abs(targetTemp - m_currentTemp); 0423 if (interval == 0) { 0424 interval = 1; 0425 } 0426 m_slowUpdateTimer->start(interval); 0427 } 0428 } 0429 0430 void NightColorManager::slowUpdate(int targetTemp) 0431 { 0432 if (!m_slowUpdateTimer) { 0433 return; 0434 } 0435 int nextTemp; 0436 if (m_currentTemp < targetTemp) { 0437 nextTemp = std::min(m_currentTemp + TEMPERATURE_STEP, targetTemp); 0438 } else { 0439 nextTemp = std::max(m_currentTemp - TEMPERATURE_STEP, targetTemp); 0440 } 0441 commitGammaRamps(nextTemp); 0442 if (nextTemp == targetTemp) { 0443 // stop timer, we reached the target temp 0444 m_slowUpdateTimer.reset(); 0445 } 0446 } 0447 0448 void NightColorManager::preview(uint previewTemp) 0449 { 0450 previewTemp = std::clamp<uint>(previewTemp, MIN_TEMPERATURE, DEFAULT_DAY_TEMPERATURE); 0451 resetQuickAdjustTimer((int)previewTemp); 0452 if (m_previewTimer) { 0453 m_previewTimer.reset(); 0454 } 0455 m_previewTimer = std::make_unique<QTimer>(); 0456 m_previewTimer->setSingleShot(true); 0457 connect(m_previewTimer.get(), &QTimer::timeout, this, &NightColorManager::stopPreview); 0458 m_previewTimer->start(15000); 0459 0460 QDBusMessage message = QDBusMessage::createMethodCall( 0461 QStringLiteral("org.kde.plasmashell"), 0462 QStringLiteral("/org/kde/osdService"), 0463 QStringLiteral("org.kde.osdService"), 0464 QStringLiteral("showText")); 0465 message.setArguments( 0466 {QStringLiteral("redshift-status-on"), 0467 i18n("Color Temperature Preview")}); 0468 QDBusConnection::sessionBus().asyncCall(message); 0469 } 0470 0471 void NightColorManager::stopPreview() 0472 { 0473 if (m_previewTimer && m_previewTimer->isActive()) { 0474 updateTransitionTimings(false); 0475 updateTargetTemperature(); 0476 resetQuickAdjustTimer(currentTargetTemp()); 0477 } 0478 } 0479 0480 void NightColorManager::updateTargetTemperature() 0481 { 0482 const int targetTemperature = mode() != NightColorMode::Constant && daylight() ? m_dayTargetTemp : m_nightTargetTemp; 0483 0484 if (m_targetTemperature == targetTemperature) { 0485 return; 0486 } 0487 0488 m_targetTemperature = targetTemperature; 0489 0490 Q_EMIT targetTemperatureChanged(); 0491 } 0492 0493 void NightColorManager::updateTransitionTimings(bool force) 0494 { 0495 const auto oldPrev = m_prev; 0496 const auto oldNext = m_next; 0497 0498 if (m_mode == NightColorMode::Constant) { 0499 setDaylight(false); 0500 m_next = DateTimes(); 0501 m_prev = DateTimes(); 0502 } else if (m_mode == NightColorMode::Timings) { 0503 const QDateTime todayNow = QDateTime::currentDateTime(); 0504 0505 const QDateTime nextMorB = QDateTime(todayNow.date().addDays(m_morning < todayNow.time()), m_morning); 0506 const QDateTime nextMorE = nextMorB.addSecs(m_trTime * 60); 0507 const QDateTime nextEveB = QDateTime(todayNow.date().addDays(m_evening < todayNow.time()), m_evening); 0508 const QDateTime nextEveE = nextEveB.addSecs(m_trTime * 60); 0509 0510 if (nextEveB < nextMorB) { 0511 setDaylight(true); 0512 m_next = DateTimes(nextEveB, nextEveE); 0513 m_prev = DateTimes(nextMorB.addDays(-1), nextMorE.addDays(-1)); 0514 } else { 0515 setDaylight(false); 0516 m_next = DateTimes(nextMorB, nextMorE); 0517 m_prev = DateTimes(nextEveB.addDays(-1), nextEveE.addDays(-1)); 0518 } 0519 } else { 0520 const QDateTime todayNow = QDateTime::currentDateTime(); 0521 0522 double lat, lng; 0523 if (m_mode == NightColorMode::Automatic) { 0524 lat = m_latAuto; 0525 lng = m_lngAuto; 0526 } else { 0527 lat = m_latFixed; 0528 lng = m_lngFixed; 0529 } 0530 0531 if (!force) { 0532 // first try by only switching the timings 0533 if (m_prev.first.date() == m_next.first.date()) { 0534 // next is evening 0535 setDaylight(true); 0536 m_prev = m_next; 0537 m_next = getSunTimings(todayNow, lat, lng, false); 0538 } else { 0539 // next is morning 0540 setDaylight(false); 0541 m_prev = m_next; 0542 m_next = getSunTimings(todayNow.addDays(1), lat, lng, true); 0543 } 0544 } 0545 0546 if (force || !checkAutomaticSunTimings()) { 0547 // in case this fails, reset them 0548 DateTimes morning = getSunTimings(todayNow, lat, lng, true); 0549 if (todayNow < morning.first) { 0550 setDaylight(false); 0551 m_prev = getSunTimings(todayNow.addDays(-1), lat, lng, false); 0552 m_next = morning; 0553 } else { 0554 DateTimes evening = getSunTimings(todayNow, lat, lng, false); 0555 if (todayNow < evening.first) { 0556 setDaylight(true); 0557 m_prev = morning; 0558 m_next = evening; 0559 } else { 0560 setDaylight(false); 0561 m_prev = evening; 0562 m_next = getSunTimings(todayNow.addDays(1), lat, lng, true); 0563 } 0564 } 0565 } 0566 } 0567 0568 if (oldPrev != m_prev) { 0569 Q_EMIT previousTransitionTimingsChanged(); 0570 } 0571 if (oldNext != m_next) { 0572 Q_EMIT scheduledTransitionTimingsChanged(); 0573 } 0574 } 0575 0576 DateTimes NightColorManager::getSunTimings(const QDateTime &dateTime, double latitude, double longitude, bool morning) const 0577 { 0578 DateTimes dateTimes = calculateSunTimings(dateTime, latitude, longitude, morning); 0579 // At locations near the poles it is possible, that we can't 0580 // calculate some or all sun timings (midnight sun). 0581 // In this case try to fallback to sensible default values. 0582 const bool beginDefined = !dateTimes.first.isNull(); 0583 const bool endDefined = !dateTimes.second.isNull(); 0584 if (!beginDefined || !endDefined) { 0585 if (beginDefined) { 0586 dateTimes.second = dateTimes.first.addMSecs(FALLBACK_SLOW_UPDATE_TIME); 0587 } else if (endDefined) { 0588 dateTimes.first = dateTimes.second.addMSecs(-FALLBACK_SLOW_UPDATE_TIME); 0589 } else { 0590 // Just use default values for morning and evening, but the user 0591 // will probably deactivate Night Color anyway if he is living 0592 // in a region without clear sun rise and set. 0593 const QTime referenceTime = morning ? QTime(6, 0) : QTime(18, 0); 0594 dateTimes.first = QDateTime(dateTime.date(), referenceTime); 0595 dateTimes.second = dateTimes.first.addMSecs(FALLBACK_SLOW_UPDATE_TIME); 0596 } 0597 } 0598 return dateTimes; 0599 } 0600 0601 bool NightColorManager::checkAutomaticSunTimings() const 0602 { 0603 if (m_prev.first.isValid() && m_prev.second.isValid() && m_next.first.isValid() && m_next.second.isValid()) { 0604 const QDateTime todayNow = QDateTime::currentDateTime(); 0605 return m_prev.first <= todayNow && todayNow < m_next.first && m_prev.first.msecsTo(m_next.first) < MSC_DAY * 23. / 24; 0606 } 0607 return false; 0608 } 0609 0610 bool NightColorManager::daylight() const 0611 { 0612 return m_daylight; 0613 } 0614 0615 int NightColorManager::currentTargetTemp() const 0616 { 0617 if (!m_running) { 0618 return DEFAULT_DAY_TEMPERATURE; 0619 } 0620 0621 if (m_mode == NightColorMode::Constant) { 0622 return m_nightTargetTemp; 0623 } 0624 0625 const QDateTime todayNow = QDateTime::currentDateTime(); 0626 0627 auto f = [this, todayNow](int target1, int target2) { 0628 if (todayNow <= m_prev.second) { 0629 double residueQuota = todayNow.msecsTo(m_prev.second) / (double)m_prev.first.msecsTo(m_prev.second); 0630 0631 double ret = (int)((1. - residueQuota) * (double)target2 + residueQuota * (double)target1); 0632 // remove single digits 0633 ret = ((int)(0.1 * ret)) * 10; 0634 return (int)ret; 0635 } else { 0636 return target2; 0637 } 0638 }; 0639 0640 if (daylight()) { 0641 return f(m_nightTargetTemp, m_dayTargetTemp); 0642 } else { 0643 return f(m_dayTargetTemp, m_nightTargetTemp); 0644 } 0645 } 0646 0647 void NightColorManager::commitGammaRamps(int temperature) 0648 { 0649 const QList<ColorDevice *> devices = kwinApp()->colorManager()->devices(); 0650 for (ColorDevice *device : devices) { 0651 device->setTemperature(temperature); 0652 } 0653 0654 setCurrentTemperature(temperature); 0655 } 0656 0657 void NightColorManager::autoLocationUpdate(double latitude, double longitude) 0658 { 0659 qCDebug(KWIN_NIGHTCOLOR, "Received new location (lat: %f, lng: %f)", latitude, longitude); 0660 0661 if (!checkLocation(latitude, longitude)) { 0662 return; 0663 } 0664 0665 // we tolerate small deviations with minimal impact on sun timings 0666 if (std::abs(m_latAuto - latitude) < 2 && std::abs(m_lngAuto - longitude) < 1) { 0667 return; 0668 } 0669 cancelAllTimers(); 0670 m_latAuto = latitude; 0671 m_lngAuto = longitude; 0672 0673 NightColorSettings *s = NightColorSettings::self(); 0674 s->setLatitudeAuto(latitude); 0675 s->setLongitudeAuto(longitude); 0676 s->save(); 0677 0678 resetAllTimers(); 0679 } 0680 0681 void NightColorManager::setEnabled(bool enabled) 0682 { 0683 if (m_active == enabled) { 0684 return; 0685 } 0686 m_active = enabled; 0687 m_skewNotifier->setActive(enabled); 0688 Q_EMIT enabledChanged(); 0689 } 0690 0691 void NightColorManager::setRunning(bool running) 0692 { 0693 if (m_running == running) { 0694 return; 0695 } 0696 m_running = running; 0697 Q_EMIT runningChanged(); 0698 } 0699 0700 void NightColorManager::setCurrentTemperature(int temperature) 0701 { 0702 if (m_currentTemp == temperature) { 0703 return; 0704 } 0705 m_currentTemp = temperature; 0706 Q_EMIT currentTemperatureChanged(); 0707 } 0708 0709 void NightColorManager::setMode(NightColorMode mode) 0710 { 0711 if (m_mode == mode) { 0712 return; 0713 } 0714 m_mode = mode; 0715 Q_EMIT modeChanged(); 0716 } 0717 0718 void NightColorManager::setDaylight(bool daylight) 0719 { 0720 if (m_daylight == daylight) { 0721 return; 0722 } 0723 m_daylight = daylight; 0724 Q_EMIT daylightChanged(); 0725 } 0726 0727 } // namespace KWin 0728 0729 #include "moc_nightcolormanager.cpp"