File indexing completed on 2024-05-19 05:37:54

0001 /*
0002     SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
0003     SPDX-FileCopyrightText: 2008 Alex Merry <alex.merry@kdemail.net>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "timeengine.h"
0009 
0010 #include <QDBusConnection>
0011 #include <QDate>
0012 #include <QSocketNotifier>
0013 #include <QStringList>
0014 #include <QTime>
0015 
0016 #ifdef Q_OS_LINUX
0017 #include <fcntl.h>
0018 #include <sys/timerfd.h>
0019 #include <unistd.h>
0020 #endif
0021 
0022 #include "debug.h"
0023 #include "timesource.h"
0024 
0025 // timezone is defined in msvc
0026 #ifdef timezone
0027 #undef timezone
0028 #endif
0029 
0030 TimeEngine::TimeEngine(QObject *parent)
0031     : Plasma5Support::DataEngine(parent)
0032 {
0033     setMinimumPollingInterval(333);
0034 
0035     // To have translated timezone names
0036     // (effectively a noop if the catalog is already present).
0037     ////KF5 port: remove this line and define TRANSLATION_DOMAIN in CMakeLists.txt instead
0038     // KLocale::global()->insertCatalog("timezones4");
0039     QTimer::singleShot(0, this, &TimeEngine::init);
0040 }
0041 
0042 TimeEngine::~TimeEngine()
0043 {
0044 }
0045 
0046 void TimeEngine::init()
0047 {
0048     QDBusConnection dbus = QDBusConnection::sessionBus();
0049     dbus.connect(QString(), QString(), QStringLiteral("org.kde.KTimeZoned"), QStringLiteral("timeZoneChanged"), this, SLOT(tzConfigChanged()));
0050 
0051 #ifdef Q_OS_LINUX
0052     // monitor for the system clock being changed
0053     auto timeChangedFd = timerfd_create(CLOCK_REALTIME, O_CLOEXEC | O_NONBLOCK);
0054     itimerspec timespec;
0055     memset(&timespec, 0, sizeof(timespec)); // set all timers to 0 seconds, which creates a timer that won't do anything
0056 
0057     int err = timerfd_settime(timeChangedFd, 3, &timespec, nullptr); // monitor for the time changing
0058     //(flags == TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET). However these are not exposed in glibc so value is hardcoded
0059     if (err) {
0060         qCWarning(DATAENGINE_TIME) << "Could not create timer with TFD_TIMER_CANCEL_ON_SET. Clock skews will not be detected. Error:"
0061                                    << qPrintable(strerror(err));
0062     }
0063 
0064     connect(this, &QObject::destroyed, [timeChangedFd]() {
0065         close(timeChangedFd);
0066     });
0067 
0068     auto notifier = new QSocketNotifier(timeChangedFd, QSocketNotifier::Read, this);
0069     connect(notifier, &QSocketNotifier::activated, this, [this](int fd) {
0070         uint64_t c;
0071         read(fd, &c, 8);
0072         clockSkewed();
0073     });
0074 #else
0075     dbus.connect(QString(), "/org/kde/kcmshell_clock", "org.kde.kcmshell_clock", "clockUpdated", this, SLOT(clockSkewed()));
0076     dbus.connect(QStringLiteral("org.kde.Solid.PowerManagement"),
0077                  QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
0078                  QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
0079                  QStringLiteral("resumingFromSuspend"),
0080                  this,
0081                  SLOT(clockSkewed()));
0082 #endif
0083 }
0084 
0085 void TimeEngine::clockSkewed()
0086 {
0087     qCDebug(DATAENGINE_TIME) << "Time engine Clock skew signaled";
0088     updateAllSources();
0089     forceImmediateUpdateOfAllVisualizations();
0090 }
0091 
0092 void TimeEngine::tzConfigChanged()
0093 {
0094     qCDebug(DATAENGINE_TIME) << "Local timezone changed signaled";
0095     TimeSource *s = qobject_cast<TimeSource *>(containerForSource(QStringLiteral("Local")));
0096 
0097     if (s) {
0098         s->setTimeZone(QStringLiteral("Local"));
0099     }
0100 
0101     updateAllSources();
0102     forceImmediateUpdateOfAllVisualizations();
0103 }
0104 
0105 QStringList TimeEngine::sources() const
0106 {
0107     QStringList sources;
0108     Q_FOREACH (const QByteArray &tz, QTimeZone::availableTimeZoneIds()) {
0109         sources << QString(tz.constData());
0110     }
0111     sources << QStringLiteral("Local");
0112     return sources;
0113 }
0114 
0115 bool TimeEngine::sourceRequestEvent(const QString &name)
0116 {
0117     addSource(new TimeSource(name, this));
0118     return true;
0119 }
0120 
0121 bool TimeEngine::updateSourceEvent(const QString &tz)
0122 {
0123     TimeSource *s = qobject_cast<TimeSource *>(containerForSource(tz));
0124 
0125     if (s) {
0126         s->updateTime();
0127         return true;
0128     }
0129 
0130     return false;
0131 }
0132 
0133 K_PLUGIN_CLASS_WITH_JSON(TimeEngine, "plasma-dataengine-time.json")
0134 
0135 #include "timeengine.moc"