diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -401,6 +401,8 @@ appmenu.cpp atoms.cpp client_machine.cpp + colorcorrection/clockskewnotifier.cpp + colorcorrection/clockskewnotifierengine.cpp colorcorrection/colorcorrectdbusinterface.cpp colorcorrection/manager.cpp colorcorrection/suncalc.cpp @@ -502,6 +504,13 @@ xwl/xwayland_interface.cpp ) +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + set(kwin_KDEINIT_SRCS + ${kwin_KDEINIT_SRCS} + colorcorrection/clockskewnotifierengine_linux.cpp + ) +endif() + include(ECMQtDeclareLoggingCategory) ecm_qt_declare_logging_category(kwin_KDEINIT_SRCS HEADER diff --git a/colorcorrection/clockskewnotifier.h b/colorcorrection/clockskewnotifier.h new file mode 100644 --- /dev/null +++ b/colorcorrection/clockskewnotifier.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 Vlad Zahorodnii + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +namespace KWin +{ + +/** + * The ClockSkewNotifier class provides a way for monitoring system clock changes. + * + * The ClockSkewNotifier class makes it possible to detect discontinuous changes to + * the system clock. Such changes are usually initiated by the user adjusting values + * in the Date and Time KCM or calls made to functions like settimeofday(). + */ +class ClockSkewNotifier : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged) + +public: + explicit ClockSkewNotifier(QObject *parent = nullptr); + ~ClockSkewNotifier() override; + + /** + * Returns @c true if the notifier is active; otherwise returns @c false. + */ + bool isActive() const; + + /** + * Sets the active status of the clock skew notifier to @p active. + * + * clockSkewed() signal won't be emitted while the notifier is inactive. + * + * The notifier is inactive by default. + * + * @see activeChanged + */ + void setActive(bool active); + +signals: + /** + * This signal is emitted whenever the active property is changed. + */ + void activeChanged(); + + /** + * This signal is emitted whenever the system clock is changed. + */ + void clockSkewed(); + +private: + class Private; + QScopedPointer d; +}; + +} // namespace KWin diff --git a/colorcorrection/clockskewnotifier.cpp b/colorcorrection/clockskewnotifier.cpp new file mode 100644 --- /dev/null +++ b/colorcorrection/clockskewnotifier.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 Vlad Zahorodnii + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "clockskewnotifier.h" +#include "clockskewnotifierengine_p.h" + +namespace KWin +{ + +class ClockSkewNotifier::Private +{ +public: + void loadNotifierEngine(); + void unloadNotifierEngine(); + + ClockSkewNotifier *notifier = nullptr; + ClockSkewNotifierEngine *engine = nullptr; + bool isActive = false; +}; + +void ClockSkewNotifier::Private::loadNotifierEngine() +{ + engine = ClockSkewNotifierEngine::create(notifier); + + if (engine) { + QObject::connect(engine, &ClockSkewNotifierEngine::clockSkewed, notifier, &ClockSkewNotifier::clockSkewed); + } +} + +void ClockSkewNotifier::Private::unloadNotifierEngine() +{ + if (!engine) { + return; + } + + QObject::disconnect(engine, &ClockSkewNotifierEngine::clockSkewed, notifier, &ClockSkewNotifier::clockSkewed); + engine->deleteLater(); + + engine = nullptr; +} + +ClockSkewNotifier::ClockSkewNotifier(QObject *parent) + : QObject(parent) + , d(new Private) +{ + d->notifier = this; +} + +ClockSkewNotifier::~ClockSkewNotifier() +{ +} + +bool ClockSkewNotifier::isActive() const +{ + return d->isActive; +} + +void ClockSkewNotifier::setActive(bool set) +{ + if (d->isActive == set) { + return; + } + + d->isActive = set; + + if (d->isActive) { + d->loadNotifierEngine(); + } else { + d->unloadNotifierEngine(); + } + + emit activeChanged(); +} + +} // namespace KWin diff --git a/colorcorrection/clockskewnotifierengine.cpp b/colorcorrection/clockskewnotifierengine.cpp new file mode 100644 --- /dev/null +++ b/colorcorrection/clockskewnotifierengine.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Vlad Zahorodnii + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "clockskewnotifierengine_p.h" +#if defined(Q_OS_LINUX) +#include "clockskewnotifierengine_linux.h" +#endif + +namespace KWin +{ + +ClockSkewNotifierEngine *ClockSkewNotifierEngine::create(QObject *parent) +{ +#if defined(Q_OS_LINUX) + return LinuxClockSkewNotifierEngine::create(parent); +#else + return nullptr; +#endif +} + +ClockSkewNotifierEngine::ClockSkewNotifierEngine(QObject *parent) + : QObject(parent) +{ +} + +} // namespace KWin diff --git a/colorcorrection/clockskewnotifierengine_linux.h b/colorcorrection/clockskewnotifierengine_linux.h new file mode 100644 --- /dev/null +++ b/colorcorrection/clockskewnotifierengine_linux.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 Vlad Zahorodnii + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include "clockskewnotifierengine_p.h" + +namespace KWin +{ + +class LinuxClockSkewNotifierEngine : public ClockSkewNotifierEngine +{ + Q_OBJECT + +public: + ~LinuxClockSkewNotifierEngine() override; + + static LinuxClockSkewNotifierEngine *create(QObject *parent); + +private Q_SLOTS: + void handleTimerCancelled(); + +private: + LinuxClockSkewNotifierEngine(int fd, QObject *parent); + + int m_fd; +}; + +} // namespace KWin diff --git a/colorcorrection/clockskewnotifierengine_linux.cpp b/colorcorrection/clockskewnotifierengine_linux.cpp new file mode 100644 --- /dev/null +++ b/colorcorrection/clockskewnotifierengine_linux.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 Vlad Zahorodnii + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "clockskewnotifierengine_linux.h" + +#include + +#include +#include +#include + +namespace KWin +{ + +LinuxClockSkewNotifierEngine *LinuxClockSkewNotifierEngine::create(QObject *parent) +{ + const int fd = timerfd_create(CLOCK_REALTIME, O_CLOEXEC | O_NONBLOCK); + if (fd == -1) { + qWarning("Couldn't create clock skew notifier engine: %s", strerror(errno)); + return nullptr; + } + + const itimerspec spec = {}; + const int ret = timerfd_settime(fd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, nullptr); + if (ret == -1) { + qWarning("Couldn't create clock skew notifier engine: %s", strerror(errno)); + close(fd); + return nullptr; + } + + return new LinuxClockSkewNotifierEngine(fd, parent); +} + +LinuxClockSkewNotifierEngine::LinuxClockSkewNotifierEngine(int fd, QObject *parent) + : ClockSkewNotifierEngine(parent) + , m_fd(fd) +{ + const QSocketNotifier *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(notifier, &QSocketNotifier::activated, this, &LinuxClockSkewNotifierEngine::handleTimerCancelled); +} + +LinuxClockSkewNotifierEngine::~LinuxClockSkewNotifierEngine() +{ + close(m_fd); +} + +void LinuxClockSkewNotifierEngine::handleTimerCancelled() +{ + uint64_t expirationCount; + read(m_fd, &expirationCount, sizeof(expirationCount)); + + emit clockSkewed(); +} + +} // namespace KWin diff --git a/colorcorrection/clockskewnotifierengine_p.h b/colorcorrection/clockskewnotifierengine_p.h new file mode 100644 --- /dev/null +++ b/colorcorrection/clockskewnotifierengine_p.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 Vlad Zahorodnii + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +namespace KWin +{ + +class ClockSkewNotifierEngine : public QObject +{ + Q_OBJECT + +public: + static ClockSkewNotifierEngine *create(QObject *parent); + +protected: + explicit ClockSkewNotifierEngine(QObject *parent); + +Q_SIGNALS: + void clockSkewed(); +}; + +} // namespace KWin diff --git a/colorcorrection/manager.h b/colorcorrection/manager.h --- a/colorcorrection/manager.h +++ b/colorcorrection/manager.h @@ -32,6 +32,7 @@ namespace KWin { +class ClockSkewNotifier; class Workspace; namespace ColorCorrect @@ -245,6 +246,7 @@ void setMode(NightColorMode mode); ColorCorrectDBusInterface *m_iface; + ClockSkewNotifier *m_skewNotifier; // Specifies whether Night Color is enabled. bool m_active; diff --git a/colorcorrection/manager.cpp b/colorcorrection/manager.cpp --- a/colorcorrection/manager.cpp +++ b/colorcorrection/manager.cpp @@ -18,6 +18,7 @@ along with this program. If not, see . *********************************************************************/ #include "manager.h" +#include "clockskewnotifier.h" #include "colorcorrectdbusinterface.h" #include "suncalc.h" #include @@ -36,15 +37,8 @@ #include #include -#include #include -#ifdef Q_OS_LINUX -#include -#endif -#include -#include - namespace KWin { namespace ColorCorrect { @@ -60,6 +54,8 @@ : QObject(parent) { m_iface = new ColorCorrectDBusInterface(this); + m_skewNotifier = new ClockSkewNotifier(this); + connect(kwinApp(), &Application::workspaceCreated, this, &Manager::init); // Display a message when Night Color is (un)inhibited. @@ -106,26 +102,7 @@ } ); -#ifdef Q_OS_LINUX - // monitor for system clock changes - from the time dataengine - auto timeChangedFd = ::timerfd_create(CLOCK_REALTIME, O_CLOEXEC | O_NONBLOCK); - ::itimerspec timespec; - //set all timers to 0, which creates a timer that won't do anything - ::memset(×pec, 0, sizeof(timespec)); - - // Monitor for the time changing (flags == TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET). - // However these are not exposed in glibc so value is hardcoded: - ::timerfd_settime(timeChangedFd, 3, ×pec, nullptr); - - connect(this, &QObject::destroyed, [timeChangedFd]() { - ::close(timeChangedFd); - }); - - auto notifier = new QSocketNotifier(timeChangedFd, QSocketNotifier::Read, this); - connect(notifier, &QSocketNotifier::activated, this, [this](int fd) { - uint64_t c; - ::read(fd, &c, 8); - + 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. @@ -150,9 +127,6 @@ resetAllTimers(); } }); -#else - // TODO: Alternative method for BSD. -#endif hardReset(); } @@ -914,6 +888,7 @@ return; } m_active = enabled; + m_skewNotifier->setActive(enabled); emit enabledChanged(); }