diff --git a/daemon/actions/bundled/handlebuttoneventsconfig.cpp b/daemon/actions/bundled/handlebuttoneventsconfig.cpp --- a/daemon/actions/bundled/handlebuttoneventsconfig.cpp +++ b/daemon/actions/bundled/handlebuttoneventsconfig.cpp @@ -104,6 +104,9 @@ if (PowerManagement::instance()->canHybridSuspend()) { box->addItem(QIcon::fromTheme("system-suspend-hybrid"), i18n("Hybrid suspend"), (uint)SuspendSession::SuspendHybridMode); } + if (PowerManagement::instance()->canSuspendThenHibernate()) { + box->addItem(QIcon::fromTheme("system-suspend-hybrid"), i18n("Suspend then Hibernate"), (uint)SuspendSession::SuspendThenHibernateMode); + } box->addItem(QIcon::fromTheme("system-shutdown"), i18n("Shut down"), (uint)SuspendSession::ShutdownMode); box->addItem(QIcon::fromTheme("system-lock-screen"), i18n("Lock screen"), (uint)SuspendSession::LockScreenMode); if (box != m_lidCloseCombo) { diff --git a/daemon/actions/bundled/suspendsession.h b/daemon/actions/bundled/suspendsession.h --- a/daemon/actions/bundled/suspendsession.h +++ b/daemon/actions/bundled/suspendsession.h @@ -49,7 +49,8 @@ LogoutDialogMode = 16, LockScreenMode = 32, TurnOffScreenMode = 64, - ToggleScreenOnOffMode = 128 + ToggleScreenOnOffMode = 128, + SuspendThenHibernateMode = 256 }; explicit SuspendSession(QObject *parent); @@ -68,6 +69,7 @@ void suspendToRam(); void suspendToDisk(); void suspendHybrid(); + void suspendThenHibernate(); Q_SIGNALS: void aboutToSuspend(); diff --git a/daemon/actions/bundled/suspendsession.cpp b/daemon/actions/bundled/suspendsession.cpp --- a/daemon/actions/bundled/suspendsession.cpp +++ b/daemon/actions/bundled/suspendsession.cpp @@ -111,7 +111,7 @@ const auto mode = static_cast(args["Type"].toUInt()); - if (mode == ToRamMode || mode == ToDiskMode || mode == SuspendHybridMode) { + if (mode == ToRamMode || mode == ToDiskMode || mode == SuspendHybridMode || mode == SuspendThenHibernateMode) { // don't suspend if shutting down if (KWorkSpace::isShuttingDown()) { qCDebug(POWERDEVIL) << "Not suspending because a shutdown is in progress"; @@ -144,6 +144,10 @@ Q_EMIT aboutToSuspend(); suspendJob = backend()->suspend(PowerDevil::BackendInterface::HybridSuspend); break; + case SuspendThenHibernateMode: + Q_EMIT aboutToSuspend(); + suspendJob = backend()->suspend(PowerDevil::BackendInterface::SuspendThenHibernate); + break; case ShutdownMode: KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmNo, KWorkSpace::ShutdownTypeHalt); break; @@ -198,6 +202,11 @@ triggerSuspendSession(ToRamMode); } +void SuspendSession::suspendThenHibernate() +{ + triggerSuspendSession(SuspendThenHibernateMode); +} + void SuspendSession::triggerSuspendSession(uint action) { trigger({ diff --git a/daemon/actions/bundled/suspendsessionconfig.cpp b/daemon/actions/bundled/suspendsessionconfig.cpp --- a/daemon/actions/bundled/suspendsessionconfig.cpp +++ b/daemon/actions/bundled/suspendsessionconfig.cpp @@ -87,6 +87,10 @@ if (PowerManagement::instance()->canHybridSuspend()) { m_comboBox->addItem(QIcon::fromTheme("system-suspend-hybrid"), i18n("Hybrid suspend"), (uint)SuspendSession::SuspendHybridMode); } + if (PowerManagement::instance()->canSuspendThenHibernate()) { + m_comboBox->addItem(QIcon::fromTheme("system-suspend-hybrid"), i18n("Suspend then Hibernate"), (uint)SuspendSession::SuspendThenHibernateMode); + } + m_comboBox->addItem(QIcon::fromTheme("system-shutdown"), i18n("Shut down"), (uint)SuspendSession::ShutdownMode); m_comboBox->addItem(QIcon::fromTheme("system-lock-screen"), i18n("Lock screen"), (uint)SuspendSession::LockScreenMode); diff --git a/daemon/backends/upower/login1suspendjob.cpp b/daemon/backends/upower/login1suspendjob.cpp --- a/daemon/backends/upower/login1suspendjob.cpp +++ b/daemon/backends/upower/login1suspendjob.cpp @@ -70,6 +70,9 @@ case PowerDevil::BackendInterface::HybridSuspend: reply = m_login1Interface->asyncCallWithArgumentList("HybridSleep", args); break; + case PowerDevil::BackendInterface::SuspendThenHibernate: + reply = m_login1Interface->asyncCallWithArgumentList("SuspendThenHibernate", args); + break; default: qCDebug(POWERDEVIL) << "Unsupported suspend method"; setError(1); diff --git a/daemon/backends/upower/powerdevilupowerbackend.cpp b/daemon/backends/upower/powerdevilupowerbackend.cpp --- a/daemon/backends/upower/powerdevilupowerbackend.cpp +++ b/daemon/backends/upower/powerdevilupowerbackend.cpp @@ -316,6 +316,11 @@ canHybridSleep.waitForFinished(); if (canHybridSleep.isValid() && (canHybridSleep.value() == QLatin1String("yes") || canHybridSleep.value() == QLatin1String("challenge"))) supported |= HybridSuspend; + + QDBusPendingReply canSuspendThenHibernate = m_login1Interface.data()->asyncCall("CanSuspendThenHibernate"); + canSuspendThenHibernate.waitForFinished(); + if (canSuspendThenHibernate.isValid() && (canSuspendThenHibernate.value() == QLatin1String("yes") || canSuspendThenHibernate.value() == QLatin1String("challenge"))) + supported |= SuspendThenHibernate; } /* There's a chance we're using ConsoleKit rather than ConsoleKit2 as the diff --git a/daemon/backends/upower/upowersuspendjob.cpp b/daemon/backends/upower/upowersuspendjob.cpp --- a/daemon/backends/upower/upowersuspendjob.cpp +++ b/daemon/backends/upower/upowersuspendjob.cpp @@ -64,7 +64,7 @@ m_upowerInterface->Hibernate(); break; default: - qCDebug(POWERDEVIL) << "This backend doesn't support hybrid mode"; + qCDebug(POWERDEVIL) << "This backend doesn't support hybrid mode or suspend then hibernate mode"; setError(1); setErrorText(i18n("Unsupported suspend method")); break; diff --git a/daemon/org.freedesktop.PowerManagement.xml b/daemon/org.freedesktop.PowerManagement.xml --- a/daemon/org.freedesktop.PowerManagement.xml +++ b/daemon/org.freedesktop.PowerManagement.xml @@ -10,6 +10,9 @@ + + + @@ -26,6 +29,9 @@ + + + diff --git a/daemon/powerdevilbackendinterface.h b/daemon/powerdevilbackendinterface.h --- a/daemon/powerdevilbackendinterface.h +++ b/daemon/powerdevilbackendinterface.h @@ -77,8 +77,9 @@ * - Standby: Processes are stopped, some hardware is deactivated (ACPI S1) * - ToRam: Most devices are deactivated, only RAM is powered (ACPI S3) * - ToDisk: State of the machine is saved to disk, and it's powered down (ACPI S4) + * - SuspendThenHibernate: Same as ToRam, but after a delay it switches to ToDisk */ - enum SuspendMethod{ UnknownSuspendMethod = 0, Standby = 1, ToRam = 2, ToDisk = 4, HybridSuspend = 8 }; + enum SuspendMethod{ UnknownSuspendMethod = 0, Standby = 1, ToRam = 2, ToDisk = 4, HybridSuspend = 8, SuspendThenHibernate = 16 }; /** * This type stores an OR combination of SuspendMethod values. diff --git a/daemon/powerdevilfdoconnector.h b/daemon/powerdevilfdoconnector.h --- a/daemon/powerdevilfdoconnector.h +++ b/daemon/powerdevilfdoconnector.h @@ -43,12 +43,14 @@ bool CanHibernate(); bool CanSuspend(); bool CanHybridSuspend(); + bool CanSuspendThenHibernate(); bool GetPowerSaveStatus(); void Suspend(); void Hibernate(); void HybridSuspend(); + void SuspendThenHibernate(); bool HasInhibit(); @@ -60,6 +62,7 @@ void CanSuspendChanged(bool canSuspend); void CanHibernateChanged(bool canHibernate); void CanHybridSuspendChanged(bool canHybridSuspend); + void CanSuspendThenHibernateChanged(bool canSuspendThenHibernate); void PowerSaveStatusChanged(bool savePower); void HasInhibitChanged(bool hasInhibit); diff --git a/daemon/powerdevilfdoconnector.cpp b/daemon/powerdevilfdoconnector.cpp --- a/daemon/powerdevilfdoconnector.cpp +++ b/daemon/powerdevilfdoconnector.cpp @@ -68,6 +68,11 @@ return m_core->backend()->supportedSuspendMethods() & PowerDevil::BackendInterface::HybridSuspend; } +bool FdoConnector::CanSuspendThenHibernate() +{ + return m_core->backend()->supportedSuspendMethods() & PowerDevil::BackendInterface::SuspendThenHibernate; +} + bool FdoConnector::GetPowerSaveStatus() { return m_core->backend()->acAdapterState() == PowerDevil::BackendInterface::Unplugged; @@ -88,6 +93,11 @@ triggerSuspendSession(BundledActions::SuspendSession::SuspendHybridMode); } +void FdoConnector::SuspendThenHibernate() +{ + triggerSuspendSession(BundledActions::SuspendSession::SuspendThenHibernateMode); +} + bool FdoConnector::HasInhibit() { return PolicyAgent::instance()->requirePolicyCheck(PolicyAgent::InterruptSession) != PolicyAgent::None; diff --git a/daemon/powerdevilpowermanagement.h b/daemon/powerdevilpowermanagement.h --- a/daemon/powerdevilpowermanagement.h +++ b/daemon/powerdevilpowermanagement.h @@ -31,12 +31,14 @@ Q_PROPERTY(bool canSuspend READ canSuspend NOTIFY canSuspendChanged) Q_PROPERTY(bool canHibernate READ canHibernate NOTIFY canHibernateChanged) Q_PROPERTY(bool canHybridSuspend READ canHybridSuspend NOTIFY canHybridSuspendChanged) + Q_PROPERTY(bool canSuspendThenHibernate READ canSuspendThenHibernate NOTIFY canSuspendThenHibernateChanged) public: virtual ~PowerManagement(); bool canSuspend() const; bool canHibernate() const; bool canHybridSuspend() const; + bool canSuspendThenHibernate() const; static PowerManagement *instance(); @@ -44,9 +46,11 @@ void suspend(); void hibernate(); void hybridSuspend(); + void suspendThenHibernate(); Q_SIGNALS: void canSuspendChanged(); + void canSuspendThenHibernateChanged(); void canHibernateChanged(); void canHybridSuspendChanged(); diff --git a/daemon/powerdevilpowermanagement.cpp b/daemon/powerdevilpowermanagement.cpp --- a/daemon/powerdevilpowermanagement.cpp +++ b/daemon/powerdevilpowermanagement.cpp @@ -45,9 +45,11 @@ void setCanSuspend(bool set); void setCanHibernate(bool set); void setCanHybridSuspend(bool set); + void setCanSuspendThenHibernate(bool set); bool serviceRegistered; bool canSuspend; + bool canSuspendThenHibernate; bool canHibernate; bool canHybridSuspend; QScopedPointer fdoPowerServiceWatcher; @@ -60,6 +62,7 @@ PowerManagement::Private::Private(PowerManagement *q) : serviceRegistered(false) , canSuspend(false) + , canSuspendThenHibernate(false) , canHibernate(false) , canHybridSuspend(false) , fdoPowerServiceWatcher(new QDBusServiceWatcher(s_fdoPowerService, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration)) @@ -71,6 +74,7 @@ { serviceRegistered = true; updateProperty(QStringLiteral("CanSuspend"), &Private::setCanSuspend); + updateProperty(QStringLiteral("CanSuspendThenHibernate"), &Private::setCanSuspendThenHibernate); updateProperty(QStringLiteral("CanHibernate"), &Private::setCanHibernate); updateProperty(QStringLiteral("CanHybridSuspend"), &Private::setCanHybridSuspend); } @@ -107,6 +111,15 @@ Q_EMIT q->canSuspendChanged(); } +void PowerManagement::Private::setCanSuspendThenHibernate(bool set) +{ + if (canSuspendThenHibernate == set) { + return; + } + canSuspendThenHibernate = set; + Q_EMIT q->canSuspendThenHibernateChanged(); +} + void PowerManagement::Private::setCanHybridSuspend(bool set) { if (canHybridSuspend == set) { @@ -132,6 +145,7 @@ d->setCanSuspend(false); d->setCanHibernate(false); d->setCanHybridSuspend(false); + d->setCanSuspendThenHibernate(false); } ); @@ -188,6 +202,21 @@ // FIXME: Whether there is a support of this mode? } +void PowerManagement::suspendThenHibernate() +{ + if(!d->serviceRegistered) { + return; + } + if(!d->canSuspendThenHibernate) { + return; + } + QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, + s_fdoPowerPath, + s_fdoPowerService, + QStringLiteral("SuspendThenHibernate")); + QDBusConnection::sessionBus().asyncCall(message); +} + bool PowerManagement::canSuspend() const { return d->canSuspend; @@ -203,6 +232,11 @@ return d->canHybridSuspend; } +bool PowerManagement::canSuspendThenHibernate() const +{ + return d->canSuspendThenHibernate; +} + } // namespace PowerDevil #include "powerdevilpowermanagement.moc" diff --git a/kcmodule/activities/activitywidget.cpp b/kcmodule/activities/activitywidget.cpp --- a/kcmodule/activities/activitywidget.cpp +++ b/kcmodule/activities/activitywidget.cpp @@ -100,6 +100,10 @@ m_ui->alwaysActionBox->addItem(QIcon::fromTheme("system-suspend-hibernate"), i18n("Hibernate"), (uint)SuspendSession::ToDiskMode); } + if (PowerDevil::PowerManagement::instance()->canSuspendThenHibernate()) { + m_ui->alwaysActionBox->addItem(QIcon::fromTheme("system-suspend-hibernate"), + i18n("Suspend then Hibernate"), (uint)SuspendSession::SuspendThenHibernateMode); + } m_ui->alwaysActionBox->addItem(QIcon::fromTheme("system-shutdown"), i18n("Shut down"), (uint)SuspendSession::ShutdownMode); m_ui->actLikeComboBox->clear();