diff --git a/kcms/ksmserver/kcmsmserver.h b/kcms/ksmserver/kcmsmserver.h --- a/kcms/ksmserver/kcmsmserver.h +++ b/kcms/ksmserver/kcmsmserver.h @@ -38,7 +38,10 @@ void defaults() override; private: + void initFirmwareSetup(); + void checkFirmwareSetupRequested(); SMServerConfigImpl* dialog; + bool m_isUefi = false; }; #endif diff --git a/kcms/ksmserver/kcmsmserver.cpp b/kcms/ksmserver/kcmsmserver.cpp --- a/kcms/ksmserver/kcmsmserver.cpp +++ b/kcms/ksmserver/kcmsmserver.cpp @@ -19,11 +19,14 @@ * along with this program; if not, write to the Free Software */ +#include +#include +#include #include +#include //Added by qt3to4: #include - #include #include #include @@ -44,6 +47,14 @@ K_PLUGIN_FACTORY(SMSFactory, registerPlugin();) +static const QString s_login1Service = QStringLiteral("org.freedesktop.login1"); +static const QString s_login1Path = QStringLiteral("/org/freedesktop/login1"); +static const QString s_dbusPropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties"); +static const QString s_login1ManagerInterface = QStringLiteral("org.freedesktop.login1.Manager"); +static const QString s_login1RebootToFirmwareSetup = QStringLiteral("RebootToFirmwareSetup"); +static const QString s_login1CanRebootToFirmwareSetup = QStringLiteral("CanRebootToFirmwareSetup"); +static const QString s_login1SetRebootToFirmwareSetup = QStringLiteral("SetRebootToFirmwareSetup"); + SMServerConfig::SMServerConfig(QWidget *parent, const QVariantList &args) : KCModule(parent, args) { @@ -59,9 +70,101 @@ dialog = new SMServerConfigImpl(this); connect(dialog, SIGNAL(changed()), SLOT(changed())); + initFirmwareSetup(); + checkFirmwareSetupRequested(); + topLayout->addWidget(dialog); } +void SMServerConfig::initFirmwareSetup() +{ + connect(dialog, &SMServerConfigImpl::firmwareSetupRequested, this, [this](bool enable) { + dialog->hideFirmwareSetupMessage(); + + QDBusMessage message = QDBusMessage::createMethodCall(s_login1Service, + s_login1Path, + s_login1ManagerInterface, + s_login1SetRebootToFirmwareSetup); + message.setArguments({enable}); + message.setInteractiveAuthorizationAllowed(true); + + QDBusPendingReply call = QDBusConnection::systemBus().asyncCall(message); + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); + connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this, enable](QDBusPendingCallWatcher *watcher) { + QDBusPendingReply reply = *watcher; + watcher->deleteLater(); + + checkFirmwareSetupRequested(); + + if (reply.isError()) { + // User likely canceled the PolKit prompt, don't show an error in this case + if (reply.error().type() != QDBusError::AccessDenied) { + dialog->showFirmwareSetupMessage(KMessageWidget::Error, + i18n("Failed to request restart to firmware setup: %1", reply.error().message())); + } + return; + } + + if (enable) { + if (m_isUefi) { + dialog->showFirmwareSetupMessage(KMessageWidget::Information, + i18n("Next time the computer is restarted, it will enter the UEFI setup screen.")); + } else { + dialog->showFirmwareSetupMessage(KMessageWidget::Information, + i18n("Next time the computer is restarted, it will enter the firmware setup screen.")); + } + } + }); + }); + + QDBusMessage message = QDBusMessage::createMethodCall(s_login1Service, + s_login1Path, + s_login1ManagerInterface, + s_login1CanRebootToFirmwareSetup); + QDBusPendingReply call = QDBusConnection::systemBus().asyncCall(message); + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); + connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { + QDBusPendingReply reply = *watcher; + watcher->deleteLater(); + + const bool canFirmwareSetup = (reply.value() == QLatin1String("yes") + || reply.value() == QLatin1String("challenge")); + + if (!canFirmwareSetup) { + return; + } + + // now check whether we're UEFI to provide a more descriptive button label + if (QFileInfo(QStringLiteral("/sys/firmware/efi")).isDir()) { + m_isUefi = true; + dialog->setFirmwareSetupTitle(i18n("UEFI Setup")); + dialog->setFirmwareSetupLabel(i18n("Enter UEFI setup on next restart")); + } + + dialog->setFirmwareSetupSupported(canFirmwareSetup); + }); +} + +void SMServerConfig::checkFirmwareSetupRequested() +{ + QDBusMessage message = QDBusMessage::createMethodCall(s_login1Service, + s_login1Path, + s_dbusPropertiesInterface, + QStringLiteral("Get")); + message.setArguments({s_login1ManagerInterface, s_login1RebootToFirmwareSetup}); + + QDBusPendingReply call = QDBusConnection::systemBus().asyncCall(message); + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); + connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { + QDBusPendingReply reply = *watcher; + watcher->deleteLater(); + + if (reply.value().isValid()) { + dialog->setFirmwareSetupChecked(reply.value().toBool()); + } + }); +} + void SMServerConfig::load() { KConfigGroup c(KSharedConfig::openConfig(QStringLiteral("ksmserverrc"), KConfig::NoGlobals), diff --git a/kcms/ksmserver/smserverconfigdlg.ui b/kcms/ksmserver/smserverconfigdlg.ui --- a/kcms/ksmserver/smserverconfigdlg.ui +++ b/kcms/ksmserver/smserverconfigdlg.ui @@ -127,6 +127,28 @@ + + + + Firmware Setup + + + + + + + + + When the computer is restarted the next time, enter firmware setup screen (e.g. UEFI or BIOS setup) + + + Enter firmware setup on next restart + + + + + + @@ -144,8 +166,10 @@ - QLineEdit -
qlineedit.h
+ KMessageWidget + QFrame +
kmessagewidget.h
+ 1
diff --git a/kcms/ksmserver/smserverconfigimpl.h b/kcms/ksmserver/smserverconfigimpl.h --- a/kcms/ksmserver/smserverconfigimpl.h +++ b/kcms/ksmserver/smserverconfigimpl.h @@ -39,12 +39,29 @@ public: SMServerConfigImpl(QWidget *parent=nullptr); ~SMServerConfigImpl() override; + + bool firmwareSetupSupported() const; + void setFirmwareSetupSupported(bool supported); + + bool firmwareSetupChecked() const; + void setFirmwareSetupChecked(bool checked); + + QString firmwareSetupTitle() const; + void setFirmwareSetupTitle(const QString &title); + + QString firmwareSetupLabel() const; + void setFirmwareSetupLabel(const QString &label); + + void showFirmwareSetupMessage(KMessageWidget::MessageType type, const QString &text); + void hideFirmwareSetupMessage(); + public Q_SLOTS: // Public slots /** No descriptions */ void configChanged(); Q_SIGNALS: // Signals /** No descriptions */ void changed(); + void firmwareSetupRequested(bool enable); }; #endif diff --git a/kcms/ksmserver/smserverconfigimpl.cpp b/kcms/ksmserver/smserverconfigimpl.cpp --- a/kcms/ksmserver/smserverconfigimpl.cpp +++ b/kcms/ksmserver/smserverconfigimpl.cpp @@ -17,6 +17,8 @@ #include "smserverconfigimpl.h" +#include + SMServerConfigImpl::SMServerConfigImpl(QWidget *parent ) : SMServerConfigDlg(parent) { connect(confirmLogoutCheck,&QAbstractButton::toggled, this, &SMServerConfigImpl::configChanged); connect(previousSessionRadio,&QAbstractButton::toggled, this, &SMServerConfigImpl::configChanged); @@ -27,6 +29,12 @@ connect(rebootRadio,&QAbstractButton::toggled, this, &SMServerConfigImpl::configChanged); connect(excludeLineedit,&QLineEdit::textChanged,this, &SMServerConfigImpl::configChanged); connect(offerShutdownCheck,&QAbstractButton::toggled,this, &SMServerConfigImpl::configChanged); + + firmwareSetupCheck->setIcon(QIcon::fromTheme(QStringLiteral("system-reboot-setup-firmware"))); + firmwareSetupBox->hide(); + connect(firmwareSetupCheck, &QCheckBox::clicked, this, &SMServerConfigImpl::firmwareSetupRequested); + + firmwareSetupMessageWidget->hide(); } SMServerConfigImpl::~SMServerConfigImpl(){ } @@ -36,3 +44,55 @@ emit changed(); } + +bool SMServerConfigImpl::firmwareSetupSupported() const +{ + return firmwareSetupBox->isVisible(); +} + +void SMServerConfigImpl::setFirmwareSetupSupported(bool supported) +{ + firmwareSetupBox->setVisible(supported); +} + +bool SMServerConfigImpl::firmwareSetupChecked() const +{ + return firmwareSetupCheck->isChecked(); +} + +void SMServerConfigImpl::setFirmwareSetupChecked(bool checked) +{ + firmwareSetupCheck->setChecked(checked); +} + +QString SMServerConfigImpl::firmwareSetupTitle() const +{ + return firmwareSetupBox->title(); +} + +void SMServerConfigImpl::setFirmwareSetupTitle(const QString &title) +{ + firmwareSetupBox->setTitle(title); +} + +QString SMServerConfigImpl::firmwareSetupLabel() const +{ + return firmwareSetupCheck->text(); +} + +void SMServerConfigImpl::setFirmwareSetupLabel(const QString &label) +{ + firmwareSetupCheck->setText(label); +} + +void SMServerConfigImpl::showFirmwareSetupMessage(KMessageWidget::MessageType type, const QString &text) +{ + firmwareSetupMessageWidget->setMessageType(type); + firmwareSetupMessageWidget->setText(text); + firmwareSetupMessageWidget->animatedShow(); +} + +void SMServerConfigImpl::hideFirmwareSetupMessage() +{ + firmwareSetupMessageWidget->animatedHide(); +}