Merge pull request #2404 from jpetso/work/jpetso/fix-2384
[libcalamares] Block sleep with systemd/CK login manager if present
This commit is contained in:
commit
714a085556
@ -17,6 +17,7 @@
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusPendingReply>
|
||||
@ -24,6 +25,8 @@
|
||||
#include <QThread>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <unistd.h> // for close()
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -36,7 +39,7 @@ namespace
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
|
||||
/** @brief Class to manage sleep / suspend on inactivity
|
||||
/** @brief Class to manage sleep / suspend on inactivity (via fd.o Inhibit service on the user bus)
|
||||
*
|
||||
* Create an object of this class on the heap. Call inhibitSleep()
|
||||
* to (try to) stop system sleep / suspend. Call uninhibitSleep()
|
||||
@ -166,20 +169,166 @@ PowerManagementInterface::uninhibitSleep()
|
||||
replyWatcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInterface::uninhibitDBusCallFinished );
|
||||
}
|
||||
|
||||
|
||||
/** @brief Class to manage sleep / suspend on inactivity (via logind/CK2 service on the system bus)
|
||||
*
|
||||
* Create an object of this class on the heap. Call inhibitSleep()
|
||||
* to (try to) stop system sleep / suspend. Call uninhibitSleep()
|
||||
* when the object is no longer needed. The object self-deletes
|
||||
* after uninhibitSleep() completes.
|
||||
*/
|
||||
class LoginManagerInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static LoginManagerInterface* makeForRegisteredService( QObject* parent = nullptr );
|
||||
~LoginManagerInterface() override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void inhibitSleep();
|
||||
void uninhibitSleep();
|
||||
|
||||
private Q_SLOTS:
|
||||
void inhibitDBusCallFinished( QDBusPendingCallWatcher* aWatcher );
|
||||
|
||||
private:
|
||||
enum class Service
|
||||
{
|
||||
Logind,
|
||||
ConsoleKit,
|
||||
};
|
||||
LoginManagerInterface( Service service, QObject* parent = nullptr );
|
||||
|
||||
int m_inhibitFd = -1;
|
||||
Service m_service;
|
||||
};
|
||||
|
||||
LoginManagerInterface*
|
||||
LoginManagerInterface::makeForRegisteredService( QObject* parent )
|
||||
{
|
||||
if ( QDBusConnection::systemBus().interface()->isServiceRegistered( QStringLiteral( "org.freedesktop.login1" ) ) )
|
||||
{
|
||||
return new LoginManagerInterface( Service::Logind, parent );
|
||||
}
|
||||
else if ( QDBusConnection::systemBus().interface()->isServiceRegistered(
|
||||
QStringLiteral( "org.freedesktop.ConsoleKit" ) ) )
|
||||
{
|
||||
return new LoginManagerInterface( Service::ConsoleKit, parent );
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LoginManagerInterface::LoginManagerInterface( Service service, QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_service( service )
|
||||
{
|
||||
}
|
||||
|
||||
LoginManagerInterface::~LoginManagerInterface() = default;
|
||||
|
||||
void
|
||||
LoginManagerInterface::inhibitDBusCallFinished( QDBusPendingCallWatcher* aWatcher )
|
||||
{
|
||||
QDBusPendingReply< uint > reply = *aWatcher;
|
||||
if ( reply.isError() )
|
||||
{
|
||||
cError() << "Could not inhibit sleep:" << reply.error();
|
||||
// m_inhibitFd = -1; // unchanged
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inhibitFd = reply.argumentAt< 0 >();
|
||||
cDebug() << "Sleep inhibited, file descriptor" << m_inhibitFd;
|
||||
}
|
||||
aWatcher->deleteLater();
|
||||
}
|
||||
|
||||
void
|
||||
LoginManagerInterface::inhibitSleep()
|
||||
{
|
||||
if ( m_inhibitFd == -1 )
|
||||
{
|
||||
cDebug() << "Sleep is already inhibited.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto systemBus = QDBusConnection::systemBus();
|
||||
QDBusMessage inhibitCall;
|
||||
|
||||
if ( m_service == Service::Logind )
|
||||
{
|
||||
inhibitCall = QDBusMessage::createMethodCall( QStringLiteral( "org.freedesktop.login1" ),
|
||||
QStringLiteral( "/org/freedesktop/login1" ),
|
||||
QStringLiteral( "org.freedesktop.login1.Manager" ),
|
||||
QStringLiteral( "Inhibit" ) );
|
||||
}
|
||||
else if ( m_service == Service::ConsoleKit )
|
||||
{
|
||||
inhibitCall = QDBusMessage::createMethodCall( QStringLiteral( "org.freedesktop.ConsoleKit" ),
|
||||
QStringLiteral( "/org/freedesktop/ConsoleKit/Manager" ),
|
||||
QStringLiteral( "org.freedesktop.ConsoleKit.Manager" ),
|
||||
QStringLiteral( "Inhibit" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
cError() << "System sleep interface not supported.";
|
||||
return;
|
||||
}
|
||||
|
||||
inhibitCall.setArguments(
|
||||
{ { "sleep:shutdown" }, { tr( "Calamares" ) }, { tr( "Installation in progress", "@status" ) }, { "block" } } );
|
||||
|
||||
auto asyncReply = systemBus.asyncCall( inhibitCall );
|
||||
auto* replyWatcher = new QDBusPendingCallWatcher( asyncReply, this );
|
||||
QObject::connect(
|
||||
replyWatcher, &QDBusPendingCallWatcher::finished, this, &LoginManagerInterface::inhibitDBusCallFinished );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LoginManagerInterface::uninhibitSleep()
|
||||
{
|
||||
if ( m_inhibitFd == -1 )
|
||||
{
|
||||
cDebug() << "Sleep was never inhibited.";
|
||||
this->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( close( m_inhibitFd ) != 0 )
|
||||
{
|
||||
cError() << "Could not uninhibit sleep:" << strerror( errno );
|
||||
}
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Calamares
|
||||
{
|
||||
SleepInhibitor::SleepInhibitor()
|
||||
{
|
||||
// Create a PowerManagementInterface object with intentionally no parent
|
||||
// Create a LoginManagerInterface object with intentionally no parent
|
||||
// so it is not destroyed along with this. Instead, when this
|
||||
// is destroyed, **start** the uninhibit-sleep call which will (later)
|
||||
// destroy the PowerManagementInterface object.
|
||||
// destroy the LoginManagerInterface object.
|
||||
if ( auto* l = LoginManagerInterface::makeForRegisteredService( nullptr ) )
|
||||
{
|
||||
l->inhibitSleep();
|
||||
connect( this, &QObject::destroyed, l, &LoginManagerInterface::uninhibitSleep );
|
||||
}
|
||||
// If no login manager service was present, try the same thing
|
||||
// with PowerManagementInterface.
|
||||
else
|
||||
{
|
||||
auto* p = new PowerManagementInterface( nullptr );
|
||||
p->inhibitSleep();
|
||||
connect( this, &QObject::destroyed, p, &PowerManagementInterface::uninhibitSleep );
|
||||
}
|
||||
}
|
||||
|
||||
SleepInhibitor::~SleepInhibitor() = default;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user