diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -73,9 +73,18 @@ endif () endif () +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + set(kcoreaddons_OPTIONAL_SRCS + ${kcoreaddons_OPTIONAL_SRCS} + clock/kclockskewnotifierengine_linux.cpp + ) +endif() + set(libkcoreaddons_SRCS kaboutdata.cpp kcoreaddons.cpp + clock/kclockskewnotifier.cpp + clock/kclockskewnotifierengine.cpp io/kautosavefile.cpp io/kdirwatch.cpp io/kfilesystemtype.cpp @@ -183,6 +192,11 @@ RELATIVE caching REQUIRED_HEADERS KCoreAddons_HEADERS ) +ecm_generate_headers(KCoreAddons_HEADERS + HEADER_NAMES KClockSkewNotifier + RELATIVE clock + REQUIRED_HEADERS KCoreAddons_HEADERS +) ecm_generate_headers(KCoreAddons_HEADERS HEADER_NAMES KAutoSaveFile @@ -258,6 +272,7 @@ kaboutdata.h kcoreaddons.h caching/kshareddatacache.h + clock/kclockskewnotifier.h io/kautosavefile.h io/kdirwatch.h io/kmessage.h diff --git a/src/lib/clock/kclockskewnotifier.h b/src/lib/clock/kclockskewnotifier.h new file mode 100644 --- /dev/null +++ b/src/lib/clock/kclockskewnotifier.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCLOCKSKEWNOTIFIER_H +#define KCLOCKSKEWNOTIFIER_H + +#include +#include + +/** + * The KClockSkewNotifier class provides a way for monitoring system clock changes. + * + * The KClockSkewNotifier 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(). + * + * @since 5.67 + */ +class KCOREADDONS_EXPORT KClockSkewNotifier : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged) + +public: + explicit KClockSkewNotifier(QObject *parent = nullptr); + ~KClockSkewNotifier() 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); + +Q_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; +}; + +#endif // KCLOCKSKEWNOTIFIER_H diff --git a/src/lib/clock/kclockskewnotifier.cpp b/src/lib/clock/kclockskewnotifier.cpp new file mode 100644 --- /dev/null +++ b/src/lib/clock/kclockskewnotifier.cpp @@ -0,0 +1,85 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kclockskewnotifier.h" +#include "kclockskewnotifierengine_p.h" + +class Q_DECL_HIDDEN KClockSkewNotifier::Private +{ +public: + void loadNotifierEngine(); + void unloadNotifierEngine(); + + KClockSkewNotifier *notifier = nullptr; + KClockSkewNotifierEngine *engine = nullptr; + bool isActive = false; +}; + +void KClockSkewNotifier::Private::loadNotifierEngine() +{ + engine = KClockSkewNotifierEngine::create(notifier); + + if (engine) { + QObject::connect(engine, &KClockSkewNotifierEngine::clockSkewed, notifier, &KClockSkewNotifier::clockSkewed); + } +} + +void KClockSkewNotifier::Private::unloadNotifierEngine() +{ + if (!engine) { + return; + } + + QObject::disconnect(engine, &KClockSkewNotifierEngine::clockSkewed, notifier, &KClockSkewNotifier::clockSkewed); + engine->deleteLater(); + + engine = nullptr; +} + +KClockSkewNotifier::KClockSkewNotifier(QObject *parent) + : QObject(parent) + , d(new Private) +{ + d->notifier = this; +} + +KClockSkewNotifier::~KClockSkewNotifier() +{ +} + +bool KClockSkewNotifier::isActive() const +{ + return d->isActive; +} + +void KClockSkewNotifier::setActive(bool active) +{ + if (d->isActive == active) { + return; + } + + d->isActive = active; + + if (d->isActive) { + d->loadNotifierEngine(); + } else { + d->unloadNotifierEngine(); + } + + emit activeChanged(); +} diff --git a/src/lib/clock/kclockskewnotifierengine.cpp b/src/lib/clock/kclockskewnotifierengine.cpp new file mode 100644 --- /dev/null +++ b/src/lib/clock/kclockskewnotifierengine.cpp @@ -0,0 +1,36 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kclockskewnotifierengine_p.h" +#if defined(Q_OS_LINUX) +#include "kclockskewnotifierengine_linux_p.h" +#endif + +KClockSkewNotifierEngine *KClockSkewNotifierEngine::create(QObject *parent) +{ +#if defined(Q_OS_LINUX) + return KLinuxClockSkewNotifierEngine::create(parent); +#else + return nullptr; +#endif +} + +KClockSkewNotifierEngine::KClockSkewNotifierEngine(QObject *parent) + : QObject(parent) +{ +} diff --git a/src/lib/clock/kclockskewnotifierengine_linux.cpp b/src/lib/clock/kclockskewnotifierengine_linux.cpp new file mode 100644 --- /dev/null +++ b/src/lib/clock/kclockskewnotifierengine_linux.cpp @@ -0,0 +1,70 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kclockskewnotifierengine_linux_p.h" +#include "kcoreaddons_debug.h" + +#include + +#include +#include +#include + +#ifndef TFD_TIMER_CANCEL_ON_SET +#define TFD_TIMER_CANCEL_ON_SET (1 << 1) +#endif + +KLinuxClockSkewNotifierEngine *KLinuxClockSkewNotifierEngine::create(QObject *parent) +{ + const int fd = timerfd_create(CLOCK_REALTIME, O_CLOEXEC | O_NONBLOCK); + if (fd == -1) { + qCWarning(KCOREADDONS_DEBUG, "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) { + qCWarning(KCOREADDONS_DEBUG, "Couldn't create clock skew notifier engine: %s", strerror(errno)); + close(fd); + return nullptr; + } + + return new KLinuxClockSkewNotifierEngine(fd, parent); +} + +KLinuxClockSkewNotifierEngine::KLinuxClockSkewNotifierEngine(int fd, QObject *parent) + : KClockSkewNotifierEngine(parent) + , m_fd(fd) +{ + const QSocketNotifier *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(notifier, &QSocketNotifier::activated, this, &KLinuxClockSkewNotifierEngine::handleTimerCancelled); +} + +KLinuxClockSkewNotifierEngine::~KLinuxClockSkewNotifierEngine() +{ + close(m_fd); +} + +void KLinuxClockSkewNotifierEngine::handleTimerCancelled() +{ + uint64_t expirationCount; + read(m_fd, &expirationCount, sizeof(expirationCount)); + + emit clockSkewed(); +} diff --git a/src/lib/clock/kclockskewnotifierengine_linux_p.h b/src/lib/clock/kclockskewnotifierengine_linux_p.h new file mode 100644 --- /dev/null +++ b/src/lib/clock/kclockskewnotifierengine_linux_p.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCLOCKSKEWNOTIFIERENGINE_LINUX_P_H +#define KCLOCKSKEWNOTIFIERENGINE_LINUX_P_H + +#include "kclockskewnotifierengine_p.h" + +class KLinuxClockSkewNotifierEngine : public KClockSkewNotifierEngine +{ + Q_OBJECT + +public: + ~KLinuxClockSkewNotifierEngine() override; + + static KLinuxClockSkewNotifierEngine *create(QObject *parent); + +private Q_SLOTS: + void handleTimerCancelled(); + +private: + KLinuxClockSkewNotifierEngine(int fd, QObject *parent); + + int m_fd; +}; + +#endif // KCLOCKSKEWNOTIFIERENGINE_LINUX_P_H diff --git a/src/lib/clock/kclockskewnotifierengine_p.h b/src/lib/clock/kclockskewnotifierengine_p.h new file mode 100644 --- /dev/null +++ b/src/lib/clock/kclockskewnotifierengine_p.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCLOCKSKEWNOTIFIERENGINE_P_H +#define KCLOCKSKEWNOTIFIERENGINE_P_H + +#include + +class KClockSkewNotifierEngine : public QObject +{ + Q_OBJECT + +public: + static KClockSkewNotifierEngine *create(QObject *parent); + +protected: + explicit KClockSkewNotifierEngine(QObject *parent); + +Q_SIGNALS: + void clockSkewed(); +}; + +#endif // KCLOCKSKEWNOTIFIERENGINE_P_H