File indexing completed on 2024-04-28 16:54:29

0001 /*
0002     SPDX-FileCopyrightText: 2009 Till Adam <adam@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "ktimezoned_win.moc"
0008 #include "ktimezonedbase.moc"
0009 
0010 #include <climits>
0011 #include <cstdlib>
0012 
0013 #include <QDBusConnection>
0014 #include <QDBusMessage>
0015 #include <QDebug>
0016 #include <QStringList>
0017 #include <QTextStream>
0018 #include <QThread>
0019 
0020 #include <kcodecs.h>
0021 #include <kconfiggroup.h>
0022 #include <kdebug.h>
0023 #include <kglobal.h>
0024 #include <klocale.h>
0025 
0026 #include <kpluginfactory.h>
0027 
0028 #ifdef Q_OS_WIN
0029 #include <Windows.h>
0030 #endif
0031 
0032 K_PLUGIN_CLASS_WITH_JSON(KTimeZoned, "ktimezoned.json")
0033 
0034 // Config file entry names
0035 const char LOCAL_ZONE[] = "LocalZone"; // name of local time zone
0036 static const TCHAR currentTimeZoneKey[] = TEXT("System\\CurrentControlSet\\Control\\TimeZoneInformation");
0037 
0038 class RegistryWatcherThread : public QThread
0039 {
0040 public:
0041     RegistryWatcherThread(KTimeZoned *parent)
0042         : QThread(parent)
0043         , q(parent)
0044     {
0045     }
0046 
0047     ~RegistryWatcherThread()
0048     {
0049         RegCloseKey(key);
0050     }
0051 
0052     void run()
0053     {
0054 // FIXME: the timezonechange needs to be handled differently
0055 #ifndef _WIN32
0056         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, currentTimeZoneKey, 0, KEY_READ, &key) == ERROR_SUCCESS) {
0057             while (true) {
0058                 RegNotifyChangeKeyValue(key, true, REG_NOTIFY_CHANGE_LAST_SET, NULL, false /*async, we want it to block*/);
0059                 q->updateLocalZone();
0060             }
0061         }
0062 #endif
0063     }
0064 
0065 private:
0066     KTimeZoned *q;
0067     HKEY key;
0068 };
0069 
0070 KTimeZoned::KTimeZoned(QObject *parent, const QList<QVariant> &l)
0071     : KTimeZonedBase(parent, l)
0072     , mRegistryWatcherThread(0)
0073 {
0074     init(false);
0075 }
0076 
0077 KTimeZoned::~KTimeZoned()
0078 {
0079     if (mRegistryWatcherThread) {
0080         mRegistryWatcherThread->quit();
0081         mRegistryWatcherThread->wait(100);
0082     }
0083     delete mRegistryWatcherThread;
0084 }
0085 
0086 void KTimeZoned::init(bool restart)
0087 {
0088     if (restart) {
0089         qDebug() << "KTimeZoned::init(restart)";
0090         delete mRegistryWatcherThread;
0091         mRegistryWatcherThread = 0;
0092     }
0093 
0094     KConfig config(QLatin1String("ktimezonedrc"));
0095     if (restart)
0096         config.reparseConfiguration();
0097     KConfigGroup group(&config, "TimeZones");
0098     mConfigLocalZone = group.readEntry(LOCAL_ZONE);
0099 
0100     updateLocalZone();
0101     if (!mRegistryWatcherThread) {
0102         mRegistryWatcherThread = new RegistryWatcherThread(this);
0103         mRegistryWatcherThread->start();
0104     }
0105 }
0106 
0107 // Check if the local zone has been updated, and if so, write the new
0108 // zone to the config file and notify interested parties.
0109 void KTimeZoned::updateLocalZone()
0110 {
0111     // On Windows, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
0112     // holds the time zone database. The TZI binary value is the TIME_ZONE_INFORMATION structure.
0113 
0114     TIME_ZONE_INFORMATION tzinfo;
0115     DWORD res = GetTimeZoneInformation(&tzinfo);
0116     if (res == TIME_ZONE_ID_INVALID)
0117         return; // hm
0118     mLocalZone = QString::fromUtf16(reinterpret_cast<ushort *>(tzinfo.StandardName));
0119 
0120     if (mConfigLocalZone != mLocalZone) {
0121         qDebug() << "Local timezone is now: " << mLocalZone;
0122         KConfig config(QLatin1String("ktimezonedrc"));
0123         KConfigGroup group(&config, "TimeZones");
0124         mConfigLocalZone = mLocalZone;
0125         group.writeEntry(LOCAL_ZONE, mConfigLocalZone);
0126         group.sync();
0127 
0128         QDBusMessage message = QDBusMessage::createSignal("/Daemon", "org.kde.KTimeZoned", "timeZoneChanged");
0129         QDBusConnection::sessionBus().send(message);
0130     }
0131 }