Commit b6ae01ca authored by David Edmundson's avatar David Edmundson
Browse files

Add systemd support into the clock KCM as an optional dependency

The current time setting helper is incredibly broken.

It manually tries to run a range of NTP utilities, all of which are
deprecated.

We can just call timedated directly and cut out the middleman as it has
uses polkit anyway.

This is currently an optional dependency, and the original helper still
exists. It makes the code messy, but we have users to support for now.

Detection is done at runtime

BUG: 196316
BUG: 311286
BUG: 317784
BUG: 319072
BUG: 337012
BUG: 339582
BUG: 241817
BUG: 178968
BUG: 320456
BUG: 317999
FEATURE: 337659
REVIEW: 122400
parent f5064e19
......@@ -5,6 +5,9 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kcmkclock\")
set(kcm_clock_PART_SRCS dtime.cpp main.cpp )
ki18n_wrap_ui(kcm_clock_PART_SRCS dateandtime.ui)
qt5_add_dbus_interface(kcm_clock_PART_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/timedated1.xml timedated_interface)
add_library(kcm_clock MODULE ${kcm_clock_PART_SRCS})
target_link_libraries(kcm_clock
......@@ -22,11 +25,12 @@ target_link_libraries(kcm_clock
install(TARGETS kcm_clock DESTINATION ${PLUGIN_INSTALL_DIR} )
########### next target ###############
#This is only needed when not using timedated and can be removed in future
add_executable(kcmdatetimehelper helper.cpp ${helper_mocs})
target_link_libraries(kcmdatetimehelper KF5::Auth KF5::ConfigCore KF5::KDELibs4Support)
install(TARGETS kcmdatetimehelper DESTINATION ${KAUTH_HELPER_INSTALL_DIR})
install(TARGETS kcmdatetimehelper DESTINATION ${KAUTH_HELPER_INSTALL_DIR})
kauth_install_helper_files(kcmdatetimehelper org.kde.kcontrol.kcmclock root)
kauth_install_actions(org.kde.kcontrol.kcmclock kcmclock_actions.actions)
......
......@@ -48,9 +48,9 @@
</spacer>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="timeServerLabel">
<property name="text">
<string>Time server:</string>
<string>&amp;Time server:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
......@@ -158,6 +158,21 @@
</item>
<item>
<widget class="K4TimeZoneWidget" name="tzonelist">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">3</string>
</property>
</column>
</widget>
</item>
</layout>
......@@ -173,25 +188,20 @@
<header>k4timezonewidget.h</header>
</customwidget>
<customwidget>
<class>KTreeWidgetSearchLine</class>
<extends>KLineEdit</extends>
<header>ktreewidgetsearchline.h</header>
<class>KDatePicker</class>
<extends>QFrame</extends>
<header>kdatepicker.h</header>
</customwidget>
<customwidget>
<class>KLineEdit</class>
<class>KTreeWidgetSearchLine</class>
<extends>QLineEdit</extends>
<header>klineedit.h</header>
<header>ktreewidgetsearchline.h</header>
</customwidget>
<customwidget>
<class>KSeparator</class>
<extends>QFrame</extends>
<header>kseparator.h</header>
</customwidget>
<customwidget>
<class>KDatePicker</class>
<extends>QFrame</extends>
<header>kdatepicker.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
......
......@@ -55,11 +55,13 @@
#include <Plasma/Svg>
#include "timedated_interface.h"
#include "helper.h"
Dtime::Dtime(QWidget * parent)
: QWidget(parent)
Dtime::Dtime(QWidget * parent, bool haveTimeDated):
QWidget(parent),
m_haveTimedated(haveTimeDated)
{
setupUi(this);
......@@ -73,18 +75,17 @@ Dtime::Dtime(QWidget * parent)
timeServerList->setEnabled(false);
timeServerList->setEditable(true);
#ifdef NO_SYSTEMD
findNTPutility();
if (ntpUtility.isEmpty()) {
QString toolTip = i18n("No NTP utility has been found. "
"Install 'ntpdate' or 'rdate' command to enable automatic "
"updating of date and time.");
setDateTimeAuto->setEnabled(false);
setDateTimeAuto->setToolTip(toolTip);
timeServerList->setToolTip(toolTip);
if (!haveTimeDated) {
findNTPutility();
if (ntpUtility.isEmpty()) {
QString toolTip = i18n("No NTP utility has been found. "
"Install 'ntpdate' or 'rdate' command to enable automatic "
"updating of date and time.");
setDateTimeAuto->setEnabled(false);
setDateTimeAuto->setToolTip(toolTip);
timeServerList->setToolTip(toolTip);
}
}
#endif
QVBoxLayout *v2 = new QVBoxLayout( timeBox );
v2->setMargin( 0 );
......@@ -196,21 +197,35 @@ void Dtime::configChanged(){
void Dtime::load()
{
// The config is actually written to the system config, but the user does not have any local config,
// since there is nothing writing it.
KConfig _config( "kcmclockrc", KConfig::NoGlobals );
KConfigGroup config(&_config, "NTP");
timeServerList->clear();
timeServerList->addItems(config.readEntry("servers",
i18n("Public Time Server (pool.ntp.org),\
asia.pool.ntp.org,\
europe.pool.ntp.org,\
north-america.pool.ntp.org,\
oceania.pool.ntp.org")).split(',', QString::SkipEmptyParts));
setDateTimeAuto->setChecked(config.readEntry("enabled", false));
if (ntpUtility.isEmpty()) {
timeServerList->setEnabled(false);
QString currentTimeZone;
if (m_haveTimedated) {
OrgFreedesktopTimedate1Interface timeDatedIface("org.freedesktop.timedate1", "/org/freedesktop/timedate1", QDBusConnection::systemBus());
//the server list is not relevant for timesyncd, it fetches it from the network
timeServerList->setVisible(false);
timeServerLabel->setVisible(false);
setDateTimeAuto->setEnabled(timeDatedIface.canNTP());
setDateTimeAuto->setChecked(timeDatedIface.nTP());
currentTimeZone = timeDatedIface.timezone();
} else {
// The config is actually written to the system config, but the user does not have any local config,
// since there is nothing writing it.
KConfig _config( "kcmclockrc", KConfig::NoGlobals );
KConfigGroup config(&_config, "NTP");
timeServerList->clear();
timeServerList->addItems(config.readEntry("servers",
i18n("Public Time Server (pool.ntp.org),\
asia.pool.ntp.org,\
europe.pool.ntp.org,\
north-america.pool.ntp.org,\
oceania.pool.ntp.org")).split(',', QString::SkipEmptyParts));
setDateTimeAuto->setChecked(config.readEntry("enabled", false));
if (ntpUtility.isEmpty()) {
timeServerList->setEnabled(false);
}
currentTimeZone = KSystemTimeZones::local().name();
}
// Reset to the current date and time
......@@ -226,8 +241,7 @@ oceania.pool.ntp.org")).split(',', QString::SkipEmptyParts));
//Timezone
currentZone();
// read the currently set time zone
tzonelist->setSelected(KSystemTimeZones::local().name(), true);
tzonelist->setSelected(currentTimeZone, true);
emit timeChanged(false);
}
......
......@@ -46,7 +46,7 @@ class Dtime : public QWidget, public Ui::DateAndTime
{
Q_OBJECT
public:
Dtime( QWidget *parent=0 );
Dtime( QWidget *parent, bool haveTimedated);
void processHelperErrors( int code );
void load();
......@@ -85,6 +85,7 @@ private:
int BufI;
bool refresh;
bool ontimeout;
bool m_haveTimedated;
};
class Kclock : public QWidget
......
......@@ -2,6 +2,7 @@
* main.cpp
*
* Copyright (C) 1998 Luca Montecchiani <m.luca@usa.net>
* Copyright (C) 2015 David Edmundson <davidedmundson@kde.org>
*
* 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
......@@ -31,7 +32,6 @@
#include <kdialog.h>
#include <kpluginfactory.h>
#include <kpluginloader.h>
#include <kprocess.h>
#include <kmessagebox.h>
#include "dtime.h"
......@@ -40,6 +40,8 @@
#include <kauthaction.h>
#include <kauthexecutejob.h>
#include "timedated_interface.h"
K_PLUGIN_FACTORY(KlockModuleFactory, registerPlugin<KclockModule>();)
K_EXPORT_PLUGIN(KlockModuleFactory("kcmkclock"))
......@@ -47,6 +49,15 @@ K_EXPORT_PLUGIN(KlockModuleFactory("kcmkclock"))
KclockModule::KclockModule(QWidget *parent, const QVariantList &)
: KCModule(parent)
{
auto reply = QDBusConnection::systemBus().call(QDBusMessage::createMethodCall("org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ListActivatableNames"));
if (!reply.arguments().isEmpty() && reply.arguments().first().value<QStringList>().contains("org.freedesktop.timedate1")) {
m_haveTimedated = true;
}
KAboutData *about =
new KAboutData(QStringLiteral("kcmclock"), i18n("KDE Clock Control Module"), QStringLiteral("1.0"),
QString(), KAboutLicense::GPL,
......@@ -62,19 +73,24 @@ KclockModule::KclockModule(QWidget *parent, const QVariantList &)
" the root password, but feel the system time should be corrected, please contact your system"
" administrator."));
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(KDialog::spacingHint());
dtime = new Dtime(this);
dtime = new Dtime(this, m_haveTimedated);
layout->addWidget(dtime);
connect(dtime, SIGNAL(timeChanged(bool)), this, SIGNAL(changed(bool)));
setButtons(Help|Apply);
setNeedsAuthorization(true);
process = NULL;
if (m_haveTimedated) {
setAuthAction(KAuth::Action("org.freedesktop.timedate1.set-time"));
} else {
//auth action name will be automatically guessed from the KCM name
qWarning() << "Timedated not found, using legacy saving mode";
setNeedsAuthorization(true);
}
}
bool KclockModule::kauthSave()
......@@ -111,11 +127,63 @@ bool KclockModule::kauthSave()
return rc;
}
bool KclockModule::timedatedSave()
{
OrgFreedesktopTimedate1Interface timedateIface("org.freedesktop.timedate1", "/org/freedesktop/timedate1", QDBusConnection::systemBus());
bool rc = true;
//final arg in each method is "user-interaction" i.e whether it's OK for polkit to ask for auth
//we cannot send requests up front then block for all replies as we need NTP to be disabled before we can make a call to SetTime
//timedated processes these in parallel and will return an error otherwise
auto reply = timedateIface.SetNTP(dtime->ntpEnabled(), true);
reply.waitForFinished();
if (reply.isError()) {
KMessageBox::error(this, i18n("Unable to change NTP settings"));
qWarning() << "Failed to enable NTP" << reply.error().name() << reply.error().message();
rc = false;
}
if (!dtime->ntpEnabled()) {
qint64 timeDiff = dtime->userTime().toMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch();
//*1000 for milliseconds -> microseconds
auto reply = timedateIface.SetTime(timeDiff * 1000, true, true);
reply.waitForFinished();
if (reply.isError()) {
KMessageBox::error(this, i18n("Unable to set current time"));
qWarning() << "Failed to set current time" << reply.error().name() << reply.error().message();
rc = false;
}
}
QString selectedTimeZone = dtime->selectedTimeZone();
if (!selectedTimeZone.isEmpty()) {
auto reply = timedateIface.SetTimezone(selectedTimeZone, true);
reply.waitForFinished();
if (reply.isError()) {
KMessageBox::error(this, i18n("Unable to set timezone"));
qWarning() << "Failed to set timezone" << reply.error().name() << reply.error().message();
rc = false;
}
}
return rc;
}
void KclockModule::save()
{
setDisabled(true);
if (kauthSave()) {
bool success = false;
if (m_haveTimedated) {
success = timedatedSave();
} else {
success = kauthSave();
}
if (success) {
QDBusMessage msg = QDBusMessage::createSignal("/org/kde/kcmshell_clock", "org.kde.kcmshell_clock", "clockUpdated");
QDBusConnection::sessionBus().send(msg);
}
......@@ -125,9 +193,14 @@ void KclockModule::save()
// timezone and reloading of data, so that the new timezone is taken into account.
// The Ultimate solution to this would be if KSTZ emitted a signal when a new
// local timezone was found.
QTimer::singleShot(5000, this, SLOT(load()));
// setDisabled(false) happens in load(), since QTimer::singleShot is non-blocking
if (!m_haveTimedated) {
QTimer::singleShot(5000, this, SLOT(load()));
} else {
load();
}
}
void KclockModule::load()
......
......@@ -27,6 +27,7 @@ class Dtime;
class QTabWidget;
class KProcess;
class OrgFreedesktopTimedate1Interface;
class KclockModule : public KCModule
{
......@@ -40,9 +41,12 @@ public:
private:
bool kauthSave();
bool timedatedSave();
QTabWidget *tab;
Dtime *dtime;
KProcess *process;
bool m_haveTimedated = false;
};
#endif // main_included
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.timedate1">
<property name="Timezone" type="s" access="read">
</property>
<property name="LocalRTC" type="b" access="read">
</property>
<property name="CanNTP" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
<property name="NTP" type="b" access="read">
</property>
<property name="NTPSynchronized" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
<property name="TimeUSec" type="t" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
<property name="RTCTimeUSec" type="t" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
<method name="SetTime">
<arg type="x" direction="in"/>
<arg type="b" direction="in"/>
<arg type="b" direction="in"/>
</method>
<method name="SetTimezone">
<arg type="s" direction="in"/>
<arg type="b" direction="in"/>
</method>
<method name="SetLocalRTC">
<arg type="b" direction="in"/>
<arg type="b" direction="in"/>
<arg type="b" direction="in"/>
</method>
<method name="SetNTP">
<arg type="b" direction="in"/>
<arg type="b" direction="in"/>
</method>
</interface>
</node>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment