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 @@ -77,6 +77,7 @@ void triggerSuspendSession(uint action); private: + bool m_suspendThenHibernateEnabled = false; int m_idleTime = 0; uint m_autoType; QVariantMap m_savedArgs; 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 @@ -134,7 +134,11 @@ switch ((Mode) (args["Type"].toUInt())) { case ToRamMode: Q_EMIT aboutToSuspend(); - suspendJob = backend()->suspend(PowerDevil::BackendInterface::ToRam); + if (m_suspendThenHibernateEnabled) { + suspendJob = backend()->suspend(PowerDevil::BackendInterface::SuspendThenHibernate); + } else { + suspendJob = backend()->suspend(PowerDevil::BackendInterface::ToRam); + } break; case ToDiskMode: Q_EMIT aboutToSuspend(); @@ -179,6 +183,9 @@ } m_autoType = config.readEntry("suspendType", 0); } + if (config.isValid() && config.hasKey("suspendThenHibernate")) { + m_suspendThenHibernateEnabled = config.readEntry("suspendThenHibernate", false); + } return true; } diff --git a/daemon/actions/bundled/suspendsessionconfig.h b/daemon/actions/bundled/suspendsessionconfig.h --- a/daemon/actions/bundled/suspendsessionconfig.h +++ b/daemon/actions/bundled/suspendsessionconfig.h @@ -24,6 +24,7 @@ #include class KComboBox; +class QCheckBox; class QSpinBox; namespace PowerDevil { @@ -43,6 +44,7 @@ private: QSpinBox *m_idleTime; + QCheckBox *m_suspendThenHibernateEnabled; KComboBox *m_comboBox; }; 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 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include "suspendsession.h" @@ -53,6 +54,12 @@ { configGroup().writeEntry< uint >("suspendType", m_comboBox->itemData(m_comboBox->currentIndex()).toUInt()); configGroup().writeEntry("idleTime", m_idleTime->value() * 60 * 1000); + if (m_suspendThenHibernateEnabled) { + configGroup().writeEntry( + "suspendThenHibernate", m_suspendThenHibernateEnabled->isChecked()); + } else { + configGroup().writeEntry("suspendThenHibernate", false); + } configGroup().sync(); } @@ -64,19 +71,24 @@ uint suspendType = configGroup().readEntry< uint >("suspendType", 0); m_comboBox->setCurrentIndex(m_comboBox->findData(suspendType)); m_idleTime->setValue((configGroup().readEntry("idleTime", 600000) / 60) / 1000); + if (m_suspendThenHibernateEnabled) { + m_suspendThenHibernateEnabled->setChecked(configGroup().readEntry("suspendThenHibernate", false)); + } } QList< QPair< QString, QWidget* > > SuspendSessionConfig::buildUi() { QWidget *tempWidget = new QWidget; QHBoxLayout *hlay = new QHBoxLayout; + m_suspendThenHibernateEnabled = new QCheckBox(i18n("While asleep, hibernate after 3 hours")); m_comboBox = new KComboBox; m_idleTime = new QSpinBox; m_idleTime->setMaximumWidth(150); m_idleTime->setMinimum(1); m_idleTime->setMaximum(360); m_idleTime->setValue(0); m_idleTime->setSuffix(i18n(" min")); + m_idleTime->setPrefix(i18n("after ")); if (PowerManagement::instance()->canSuspend()) { m_comboBox->addItem(QIcon::fromTheme("system-suspend"), i18nc("Suspend to RAM", "Sleep"), (uint)SuspendSession::ToRamMode); @@ -90,18 +102,33 @@ 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); - hlay->addWidget(m_idleTime); hlay->addWidget(m_comboBox); + hlay->addWidget(m_idleTime); hlay->addStretch(); tempWidget->setLayout(hlay); QList< QPair< QString, QWidget* > > retlist; - retlist.append(qMakePair< QString, QWidget* >(i18n("After"), tempWidget)); + retlist.append(qMakePair< QString, QWidget* >(i18n("Automatically"), tempWidget)); connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged())); connect(m_idleTime, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + if (PowerManagement::instance()->canSuspendThenHibernate()) { + connect(m_suspendThenHibernateEnabled, SIGNAL(changed(bool)), this, SLOT(onChanged(bool))); + retlist.append(qMakePair< QString, QWidget* >(QLatin1Literal("NONE"), m_suspendThenHibernateEnabled)); + } else { + m_suspendThenHibernateEnabled->deleteLater(); + m_suspendThenHibernateEnabled = nullptr; + } + + int comboBoxMaxWidth = 300; + if (m_suspendThenHibernateEnabled) { + comboBoxMaxWidth = qMax(comboBoxMaxWidth, m_suspendThenHibernateEnabled->sizeHint().width()); + m_suspendThenHibernateEnabled->setMinimumWidth(300); + m_suspendThenHibernateEnabled->setMaximumWidth(comboBoxMaxWidth); + } + return retlist; } 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; diff --git a/daemon/powerdevilpowermanagement.h b/daemon/powerdevilpowermanagement.h --- a/daemon/powerdevilpowermanagement.h +++ b/daemon/powerdevilpowermanagement.h @@ -31,22 +31,26 @@ 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(); public Q_SLOTS: 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"