From kde-commits Fri Sep 21 15:48:00 2012 From: Lukas Tinkl Date: Fri, 21 Sep 2012 15:48:00 +0000 To: kde-commits Subject: [kde-workspace] powerdevil/daemon: implement systemd support for PowerDevil Policy Agent Message-Id: <20120921154800.12D86A60A6 () git ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=134824249402138 Git commit dfb0ac5cf26df411a0374e322b741278ee8eca67 by Lukas Tinkl. Committed on 21/09/2012 at 14:58. Pushed by lukas into branch 'master'. implement systemd support for PowerDevil Policy Agent This enables PowerDevil to react on active session changes (correct locking, screen brightness) on systems w/o ConsoleKit, like Fedora 18 Fixes e.g. https://bugzilla.redhat.com/show_bug.cgi?id=3D849334 REVIEW: 106506 M +216 -54 powerdevil/daemon/powerdevilpolicyagent.cpp M +24 -5 powerdevil/daemon/powerdevilpolicyagent.h http://commits.kde.org/kde-workspace/dfb0ac5cf26df411a0374e322b741278ee8eca= 67 diff --git a/powerdevil/daemon/powerdevilpolicyagent.cpp b/powerdevil/daemo= n/powerdevilpolicyagent.cpp index 5ba595b..d971721 100644 --- a/powerdevil/daemon/powerdevilpolicyagent.cpp +++ b/powerdevil/daemon/powerdevilpolicyagent.cpp @@ -1,5 +1,6 @@ /*************************************************************************= ** * Copyright (C) 2010 by Dario Freddi = * + * Copyright (C) 2012 Luk=C3=A1=C5=A1 Tinkl = * * = * * 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 = * @@ -20,6 +21,12 @@ = #include "powerdevilpolicyagent.h" = +#include +#include +#include +#include +#include + #include #include #include @@ -29,13 +36,39 @@ #include #include = +struct NamedDBusObjectPath +{ + QString name; + QDBusObjectPath path; +}; + +// Marshall the NamedDBusObjectPath data into a D-Bus argument +QDBusArgument &operator<<(QDBusArgument &argument, const NamedDBusObjectPa= th &namedPath) +{ + argument.beginStructure(); + argument << namedPath.name << namedPath.path; + argument.endStructure(); + return argument; +} + +// Retrieve the NamedDBusObjectPath data from the D-Bus argument +const QDBusArgument &operator>>(const QDBusArgument &argument, NamedDBusOb= jectPath &namedPath) +{ + argument.beginStructure(); + argument >> namedPath.name >> namedPath.path; + argument.endStructure(); + return argument; +} + +Q_DECLARE_METATYPE(NamedDBusObjectPath) + namespace PowerDevil { = class PolicyAgentHelper { public: - PolicyAgentHelper() : q(0) {} + PolicyAgentHelper() : q(0) { } ~PolicyAgentHelper() { delete q; } @@ -55,10 +88,12 @@ PolicyAgent *PolicyAgent::instance() = PolicyAgent::PolicyAgent(QObject* parent) : QObject(parent) + , m_sdAvailable(false) , m_ckAvailable(false) , m_sessionIsBeingInterrupted(false) , m_lastCookie(0) , m_busWatcher(new QDBusServiceWatcher(this)) + , m_sdWatcher(new QDBusServiceWatcher(this)) , m_ckWatcher(new QDBusServiceWatcher(this)) { Q_ASSERT(!s_globalPolicyAgent->q); @@ -72,19 +107,34 @@ PolicyAgent::~PolicyAgent() = void PolicyAgent::init() { + // Watch over the systemd service + m_sdWatcher.data()->setConnection(QDBusConnection::systemBus()); + m_sdWatcher.data()->setWatchMode(QDBusServiceWatcher::WatchForUnregist= ration | + QDBusServiceWatcher::WatchForRegistra= tion); + m_sdWatcher.data()->addWatchedService(SYSTEMD_LOGIN1_SERVICE); + + connect(m_sdWatcher.data(), SIGNAL(serviceRegistered(QString)), + this, SLOT(onSessionHandlerRegistered(QString))); + connect(m_sdWatcher.data(), SIGNAL(serviceUnregistered(QString)), + this, SLOT(onSessionHandlerUnregistered(QString))); + // If it's up and running already, let's cache it + if (QDBusConnection::systemBus().interface()->isServiceRegistered(SYST= EMD_LOGIN1_SERVICE)) { + onSessionHandlerRegistered(SYSTEMD_LOGIN1_SERVICE); + } + // Watch over the ConsoleKit service m_ckWatcher.data()->setConnection(QDBusConnection::sessionBus()); m_ckWatcher.data()->setWatchMode(QDBusServiceWatcher::WatchForUnregist= ration | QDBusServiceWatcher::WatchForRegistra= tion); - m_ckWatcher.data()->addWatchedService("org.freedesktop.ConsoleKit"); + m_ckWatcher.data()->addWatchedService(CONSOLEKIT_SERVICE); = connect(m_ckWatcher.data(), SIGNAL(serviceRegistered(QString)), - this, SLOT(onConsoleKitRegistered(QString))); + this, SLOT(onSessionHandlerRegistered(QString))); connect(m_ckWatcher.data(), SIGNAL(serviceUnregistered(QString)), - this, SLOT(onConsoleKitUnregistered(QString))); + this, SLOT(onSessionHandlerUnregistered(QString))); // If it's up and running already, let's cache it - if (QDBusConnection::systemBus().interface()->isServiceRegistered("org= .freedesktop.ConsoleKit")) { - onConsoleKitRegistered("org.freedesktop.ConsoleKit"); + if (QDBusConnection::systemBus().interface()->isServiceRegistered(CONS= OLEKIT_SERVICE)) { + onSessionHandlerRegistered(CONSOLEKIT_SERVICE); } = // Now set up our service watcher @@ -95,75 +145,176 @@ void PolicyAgent::init() this, SLOT(onServiceUnregistered(QString))); } = -void PowerDevil::PolicyAgent::onConsoleKitRegistered(const QString& ) +QString PolicyAgent::getNamedPathProperty(const QString &path, const QStri= ng &iface, const QString &prop) const { - m_ckAvailable =3D true; + QDBusMessage message =3D QDBusMessage::createMethodCall(SYSTEMD_LOGIN1= _SERVICE, path, + QLatin1String("o= rg.freedesktop.DBus.Properties"), QLatin1String("Get")); + message << iface << prop; + QDBusMessage reply =3D QDBusConnection::systemBus().call(message); + + QVariantList args =3D reply.arguments(); + if (!args.isEmpty()) { + NamedDBusObjectPath namedPath; + args.at(0).value().variant().value() = >> namedPath; + return namedPath.path.path(); + } = - // Otherwise, let's ask ConsoleKit - QDBusInterface ckiface("org.freedesktop.ConsoleKit", "/org/freedesktop= /ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", QDBusConn= ection::systemBus()); + return QString(); +} = - QDBusPendingReply sessionPath =3D ckiface.asyncCall("= GetCurrentSession"); +void PolicyAgent::onSessionHandlerRegistered(const QString & serviceName) +{ + if (serviceName =3D=3D SYSTEMD_LOGIN1_SERVICE) { + m_sdAvailable =3D true; = - sessionPath.waitForFinished(); + qRegisterMetaType(); + qDBusRegisterMetaType(); = - if (!sessionPath.isValid() || sessionPath.value().path().isEmpty()) { - kDebug() << "The session is not registered with ck"; - m_ckAvailable =3D false; - return; - } + // get the current session + QDBusInterface managerIface(SYSTEMD_LOGIN1_SERVICE, SYSTEMD_LOGIN1= _PATH, SYSTEMD_LOGIN1_MANAGER_IFACE, QDBusConnection::systemBus()); + QDBusPendingReply session =3D managerIface.asyncC= all(QLatin1String("GetSessionByPID"), (quint32) QCoreApplication::applicati= onPid()); + session.waitForFinished(); = - m_ckSessionInterface =3D new QDBusInterface("org.freedesktop.ConsoleKi= t", sessionPath.value().path(), - "org.freedesktop.ConsoleKit.= Session", QDBusConnection::systemBus()); + if (!session.isValid()) { + kDebug() << "The session is not registered with systemd"; + m_sdAvailable =3D false; + return; + } = - if (!m_ckSessionInterface.data()->isValid()) { - // As above - kDebug() << "Can't contact iface"; - m_ckAvailable =3D false; - return; - } + QString sessionPath =3D session.value().path(); + kDebug() << "Session path:" << sessionPath; + + m_sdSessionInterface =3D new QDBusInterface(SYSTEMD_LOGIN1_SERVICE= , sessionPath, + SYSTEMD_LOGIN1_SESSION_I= FACE, QDBusConnection::systemBus(), this); + if (!m_sdSessionInterface.data()->isValid()) { + // As above + kDebug() << "Can't contact session iface"; + m_sdAvailable =3D false; + delete m_sdSessionInterface.data(); + return; + } = - // Now let's obtain the seat - QDBusPendingReply< QDBusObjectPath > seatPath =3D m_ckSessionInterface= .data()->asyncCall("GetSeatId"); - seatPath.waitForFinished(); = - if (!sessionPath.isValid() || sessionPath.value().path().isEmpty()) { - kDebug() << "Unable to associate ck session with a seat"; - m_ckAvailable =3D false; - return; - } + // now let's obtain the seat + QString seatPath =3D getNamedPathProperty(sessionPath, SYSTEMD_LOG= IN1_SESSION_IFACE, "Seat"); = - if (!QDBusConnection::systemBus().connect("org.freedesktop.ConsoleKit"= , seatPath.value().path(), - "org.freedesktop.ConsoleKit.= Seat", "ActiveSessionChanged", - this, SLOT(onConsoleKitActiv= eSessionChanged(QString)))) { - kDebug() << "Unable to connect to ActiveSessionChanged"; - m_ckAvailable =3D false; - return; - } + if (seatPath.isEmpty() || seatPath =3D=3D "/") { + kDebug() << "Unable to associate systemd session with a seat" = << seatPath; + m_sdAvailable =3D false; + return; + } = - // Force triggering of active session changed - QDBusMessage call =3D QDBusMessage::createMethodCall("org.freedesktop.= ConsoleKit", seatPath.value().path(), - "org.freedesktop.Co= nsoleKit.Seat", "GetActiveSession"); - QDBusPendingReply< QDBusObjectPath > activeSession =3D QDBusConnection= ::systemBus().asyncCall(call); - activeSession.waitForFinished(); + // get the current seat + m_sdSeatInterface =3D new QDBusInterface(SYSTEMD_LOGIN1_SERVICE, s= eatPath, + SYSTEMD_LOGIN1_SEAT_IFACE, = QDBusConnection::systemBus(), this); = - onConsoleKitActiveSessionChanged(activeSession.value().path()); + if (!m_sdSeatInterface.data()->isValid()) { + // As above + kDebug() << "Can't contact seat iface"; + m_sdAvailable =3D false; + delete m_sdSeatInterface.data(); + return; + } = - kDebug() << "ConsoleKit support initialized"; + // finally get the active session path and watch for its changes + m_activeSessionPath =3D getNamedPathProperty(seatPath, SYSTEMD_LOG= IN1_SEAT_IFACE, "ActiveSession"); + + kDebug() << "ACTIVE SESSION PATH:" << m_activeSessionPath; + QDBusConnection::systemBus().connect(SYSTEMD_LOGIN1_SERVICE, seatP= ath, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, + SLOT(onActiveSessionChanged(Q= String,QVariantMap,QStringList))); + + onActiveSessionChanged(m_activeSessionPath); + + kDebug() << "systemd support initialized"; + } else if (serviceName =3D=3D CONSOLEKIT_SERVICE) { + m_ckAvailable =3D true; + + // Otherwise, let's ask ConsoleKit + QDBusInterface ckiface(CONSOLEKIT_SERVICE, "/org/freedesktop/Conso= leKit/Manager", + "org.freedesktop.ConsoleKit.Manager", QDBus= Connection::systemBus()); + + QDBusPendingReply sessionPath =3D ckiface.asyncCa= ll("GetCurrentSession"); + + sessionPath.waitForFinished(); + + if (!sessionPath.isValid() || sessionPath.value().path().isEmpty()= ) { + kDebug() << "The session is not registered with ck"; + m_ckAvailable =3D false; + return; + } + + m_ckSessionInterface =3D new QDBusInterface(CONSOLEKIT_SERVICE, se= ssionPath.value().path(), + "org.freedesktop.Console= Kit.Session", QDBusConnection::systemBus()); + + if (!m_ckSessionInterface.data()->isValid()) { + // As above + kDebug() << "Can't contact iface"; + m_ckAvailable =3D false; + return; + } + + // Now let's obtain the seat + QDBusPendingReply< QDBusObjectPath > seatPath =3D m_ckSessionInter= face.data()->asyncCall("GetSeatId"); + seatPath.waitForFinished(); + + if (!seatPath.isValid() || seatPath.value().path().isEmpty()) { + kDebug() << "Unable to associate ck session with a seat"; + m_ckAvailable =3D false; + return; + } + + if (!QDBusConnection::systemBus().connect(CONSOLEKIT_SERVICE, seat= Path.value().path(), + "org.freedesktop.Console= Kit.Seat", "ActiveSessionChanged", + this, SLOT(onActiveSessi= onChanged(QString)))) { + kDebug() << "Unable to connect to ActiveSessionChanged"; + m_ckAvailable =3D false; + return; + } + + // Force triggering of active session changed + QDBusMessage call =3D QDBusMessage::createMethodCall(CONSOLEKIT_SE= RVICE, seatPath.value().path(), + "org.freedeskto= p.ConsoleKit.Seat", "GetActiveSession"); + QDBusPendingReply< QDBusObjectPath > activeSession =3D QDBusConnec= tion::systemBus().asyncCall(call); + activeSession.waitForFinished(); + + onActiveSessionChanged(activeSession.value().path()); + + kDebug() << "ConsoleKit support initialized"; + } + else + kdWarning() << "Unhandled service registered:" << serviceName; } = -void PowerDevil::PolicyAgent::onConsoleKitUnregistered(const QString& ) +void PolicyAgent::onSessionHandlerUnregistered(const QString & serviceName) { - m_ckAvailable =3D false; - m_ckSessionInterface.data()->deleteLater(); + if (serviceName =3D=3D SYSTEMD_LOGIN1_SERVICE) { + m_sdAvailable =3D false; + delete m_sdSessionInterface.data(); + } + else if (serviceName =3D=3D CONSOLEKIT_SERVICE) { + m_ckAvailable =3D false; + delete m_ckSessionInterface.data(); + } } = -void PolicyAgent::onConsoleKitActiveSessionChanged(const QString& activeSe= ssion) +void PolicyAgent::onActiveSessionChanged(const QString & ifaceName, const = QVariantMap & changedProps, const QStringList & invalidatedProps) { - if (activeSession.isEmpty()) { + const QString key =3D QLatin1String("ActiveSession"); + + if (ifaceName =3D=3D SYSTEMD_LOGIN1_SEAT_IFACE && (changedProps.keys()= .contains(key) || invalidatedProps.contains(key))) { + m_activeSessionPath =3D getNamedPathProperty(m_sdSeatInterface.dat= a()->path(), SYSTEMD_LOGIN1_SEAT_IFACE, key); + kDebug() << "ACTIVE SESSION PATH CHANGED:" << m_activeSessionPath; + onActiveSessionChanged(m_activeSessionPath); + } +} + +void PolicyAgent::onActiveSessionChanged(const QString& activeSession) +{ + if (activeSession.isEmpty() || activeSession =3D=3D "/") { kDebug() << "Switched to inactive session - leaving unchanged"; return; - } else if (activeSession =3D=3D m_ckSessionInterface.data()->path()) { + } else if ((!m_sdSessionInterface.isNull() && activeSession =3D=3D m_s= dSessionInterface.data()->path()) || + (!m_ckSessionInterface.isNull() && activeSession =3D=3D m_c= kSessionInterface.data()->path())) { kDebug() << "Current session is now active"; m_wasLastActiveSession =3D true; } else { @@ -201,6 +352,17 @@ PolicyAgent::RequiredPolicies PolicyAgent::unavailable= Policies() = PolicyAgent::RequiredPolicies PolicyAgent::requirePolicyCheck(PolicyAgent:= :RequiredPolicies policies) { + if (!m_sdAvailable) { + // No way to determine if we are on the current session, simply su= ppose we are + kDebug() << "Can't contact systemd"; + } else if (!m_sdSessionInterface.isNull()) { + bool isActive =3D m_sdSessionInterface.data()->property("Active").= toBool(); + + if (!isActive && !m_wasLastActiveSession && policies !=3D Interrup= tSession) { + return policies; + } + } + if (!m_ckAvailable) { // No way to determine if we are on the current session, simply su= ppose we are kDebug() << "Can't contact ck"; diff --git a/powerdevil/daemon/powerdevilpolicyagent.h b/powerdevil/daemon/= powerdevilpolicyagent.h index f637f1e..6001846 100644 --- a/powerdevil/daemon/powerdevilpolicyagent.h +++ b/powerdevil/daemon/powerdevilpolicyagent.h @@ -1,5 +1,6 @@ /*************************************************************************= ** * Copyright (C) 2010 by Dario Freddi = * + * Copyright (C) 2012 Luk=C3=A1=C5=A1 Tinkl = * * = * * 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 = * @@ -32,6 +33,15 @@ class QDBusServiceWatcher; class QDBusInterface; = +#define SYSTEMD_LOGIN1_SERVICE "org.freedesktop.login1" +#define SYSTEMD_LOGIN1_PATH "/org/freedesktop/login1" +#define SYSTEMD_LOGIN1_MANAGER_IFACE "org.freedesktop.login1.Manager" +#define SYSTEMD_LOGIN1_SESSION_IFACE "org.freedesktop.login1.Session" +#define SYSTEMD_LOGIN1_SEAT_IFACE "org.freedesktop.login1.Seat" + +#define CONSOLEKIT_SERVICE "org.freedesktop.ConsoleKit" + + namespace PowerDevil { = @@ -69,15 +79,15 @@ public Q_SLOTS: void ReleaseInhibition(uint cookie); = void releaseAllInhibitions(); - Q_SIGNALS: void unavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolic= ies newpolicies); = private Q_SLOTS: - void onServiceUnregistered(const QString &serviceName); - void onConsoleKitRegistered(const QString&); - void onConsoleKitUnregistered(const QString&); - void onConsoleKitActiveSessionChanged(const QString &activeSession); + void onServiceUnregistered(const QString & serviceName); + void onSessionHandlerRegistered(const QString & serviceName); + void onSessionHandlerUnregistered(const QString & serviceName); + void onActiveSessionChanged(const QString & ifaceName, const QVariantM= ap & changedProps, const QStringList & invalidatedProps); + void onActiveSessionChanged(const QString &activeSession); = private: explicit PolicyAgent(QObject* parent =3D 0); @@ -92,6 +102,14 @@ private: uint addInhibitionWithExplicitDBusService(uint types, const QString &a= ppName, const QString &reason, const= QString &service); = + // systemd support + QString getNamedPathProperty(const QString & path, const QString & ifa= ce, const QString & prop) const; + bool m_sdAvailable; + QString m_activeSessionPath; + QWeakPointer< QDBusInterface > m_sdSessionInterface; + QWeakPointer< QDBusInterface > m_sdSeatInterface; + + // ConsoleKit support bool m_ckAvailable; QWeakPointer< QDBusInterface > m_ckSessionInterface; QWeakPointer< QDBusInterface > m_ckSeatInterface; @@ -104,6 +122,7 @@ private: uint m_lastCookie; = QWeakPointer< QDBusServiceWatcher > m_busWatcher; + QWeakPointer< QDBusServiceWatcher > m_sdWatcher; QWeakPointer< QDBusServiceWatcher > m_ckWatcher; = bool m_wasLastActiveSession;