File indexing completed on 2022-05-16 17:44:53
0001 /******************************************************************** 0002 KSld - the KDE Screenlocker Daemon 0003 This file is part of the KDE project. 0004 0005 Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 This program is free software; you can redistribute it and/or modify 0008 it under the terms of the GNU General Public License as published by 0009 the Free Software Foundation; either version 2 of the License, or 0010 (at your option) any later version. 0011 0012 This program is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with this program. If not, see <http://www.gnu.org/licenses/>. 0019 *********************************************************************/ 0020 #include "logind.h" 0021 0022 #include <KLocalizedString> 0023 0024 #include <QCoreApplication> 0025 #include <QDBusConnectionInterface> 0026 #include <QDBusServiceWatcher> 0027 #include <QStandardPaths> 0028 0029 #include <kscreenlocker_logging.h> 0030 0031 const static QString s_login1Service = QStringLiteral("org.freedesktop.login1"); 0032 const static QString s_login1Path = QStringLiteral("/org/freedesktop/login1"); 0033 const static QString s_login1ManagerInterface = QStringLiteral("org.freedesktop.login1.Manager"); 0034 const static QString s_login1SessionInterface = QStringLiteral("org.freedesktop.login1.Session"); 0035 0036 const static QString s_consolekitService = QStringLiteral("org.freedesktop.ConsoleKit"); 0037 const static QString s_consolekitPath = QStringLiteral("/org/freedesktop/ConsoleKit/Manager"); 0038 const static QString s_consolekitManagerInterface = QStringLiteral("org.freedesktop.ConsoleKit.Manager"); 0039 const static QString s_consolekitSessionInterface = QStringLiteral("org.freedesktop.ConsoleKit.Session"); 0040 0041 const static QString s_propertyInterface = QStringLiteral("org.freedesktop.DBus.Properties"); 0042 0043 LogindIntegration::LogindIntegration(const QDBusConnection &connection, QObject *parent) 0044 : QObject(parent) 0045 , m_bus(connection) 0046 , m_logindServiceWatcher( 0047 new QDBusServiceWatcher(s_login1Service, m_bus, QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration, this)) 0048 , m_connected(false) 0049 , m_inhibitFileDescriptor() 0050 , m_service(nullptr) 0051 , m_path(nullptr) 0052 , m_managerInterface(nullptr) 0053 , m_sessionInterface(nullptr) 0054 { 0055 // if we are inside Kwin's unit tests don't query or manipulate logind 0056 // avoid connecting but keep all stubs in place 0057 if (QStandardPaths::isTestModeEnabled()) { 0058 return; 0059 } 0060 0061 connect(m_logindServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &LogindIntegration::logindServiceRegistered); 0062 connect(m_logindServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() { 0063 m_connected = false; 0064 m_sessionPath = QString(); 0065 Q_EMIT connectedChanged(); 0066 }); 0067 0068 // check whether the logind service is registered 0069 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"), 0070 QStringLiteral("/"), 0071 QStringLiteral("org.freedesktop.DBus"), 0072 QStringLiteral("ListNames")); 0073 QDBusPendingReply<QStringList> async = m_bus.asyncCall(message); 0074 QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this); 0075 connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) { 0076 QDBusPendingReply<QStringList> reply = *self; 0077 self->deleteLater(); 0078 if (!reply.isValid()) { 0079 return; 0080 } 0081 if (reply.value().contains(s_login1Service)) { 0082 logindServiceRegistered(); 0083 // Don't register ck if we have logind 0084 return; 0085 } 0086 if (reply.value().contains(s_consolekitService)) { 0087 consolekitServiceRegistered(); 0088 } 0089 }); 0090 } 0091 0092 LogindIntegration::LogindIntegration(QObject *parent) 0093 : LogindIntegration(QDBusConnection::systemBus(), parent) 0094 { 0095 } 0096 0097 LogindIntegration::~LogindIntegration() = default; 0098 0099 void LogindIntegration::logindServiceRegistered() 0100 { 0101 // get the current session 0102 QDBusMessage message = QDBusMessage::createMethodCall(s_login1Service, s_login1Path, s_login1ManagerInterface, QStringLiteral("GetSession")); 0103 message.setArguments({QStringLiteral("auto")}); 0104 QDBusPendingReply<QDBusObjectPath> session = m_bus.asyncCall(message); 0105 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(session, this); 0106 0107 m_service = &s_login1Service; 0108 m_path = &s_login1Path; 0109 m_managerInterface = &s_login1ManagerInterface; 0110 m_sessionInterface = &s_login1SessionInterface; 0111 0112 commonServiceRegistered(watcher); 0113 } 0114 0115 void LogindIntegration::consolekitServiceRegistered() 0116 { 0117 // Don't try to register with ck if we have logind 0118 if (m_connected) { 0119 return; 0120 } 0121 0122 // get the current session 0123 QDBusMessage message = 0124 QDBusMessage::createMethodCall(s_consolekitService, s_consolekitPath, s_consolekitManagerInterface, QStringLiteral("GetCurrentSession")); 0125 QDBusPendingReply<QDBusObjectPath> session = m_bus.asyncCall(message); 0126 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(session, this); 0127 0128 m_service = &s_consolekitService; 0129 m_path = &s_consolekitPath; 0130 m_managerInterface = &s_consolekitManagerInterface; 0131 m_sessionInterface = &s_consolekitSessionInterface; 0132 0133 commonServiceRegistered(watcher); 0134 } 0135 0136 void LogindIntegration::commonServiceRegistered(QDBusPendingCallWatcher *watcher) 0137 { 0138 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) { 0139 QDBusPendingReply<QDBusObjectPath> reply = *self; 0140 self->deleteLater(); 0141 if (m_connected) { 0142 return; 0143 } 0144 if (!reply.isValid()) { 0145 qCDebug(KSCREENLOCKER) << "The session is not registered: " << reply.error().message(); 0146 return; 0147 } 0148 m_sessionPath = reply.value().path(); 0149 qCDebug(KSCREENLOCKER) << "Session path:" << m_sessionPath; 0150 0151 // connections need to be done this way as the object exposes both method and signal 0152 // with name "Lock"/"Unlock". Qt is not able to automatically handle this. 0153 m_bus.connect(*m_service, m_sessionPath, *m_sessionInterface, QStringLiteral("Lock"), this, SIGNAL(requestLock())); 0154 m_bus.connect(*m_service, m_sessionPath, *m_sessionInterface, QStringLiteral("Unlock"), this, SIGNAL(requestUnlock())); 0155 m_connected = true; 0156 Q_EMIT connectedChanged(); 0157 }); 0158 0159 // connect to manager object's signals we need 0160 m_bus.connect(*m_service, *m_path, *m_managerInterface, QStringLiteral("PrepareForSleep"), this, SIGNAL(prepareForSleep(bool))); 0161 } 0162 0163 void LogindIntegration::inhibit() 0164 { 0165 if (m_inhibitFileDescriptor.isValid()) { 0166 return; 0167 } 0168 0169 if (!m_connected) { 0170 return; 0171 } 0172 0173 QDBusMessage message = QDBusMessage::createMethodCall(*m_service, *m_path, *m_managerInterface, QStringLiteral("Inhibit")); 0174 message.setArguments(QVariantList( 0175 {QStringLiteral("sleep"), i18n("Screen Locker"), i18n("Ensuring that the screen gets locked before going to sleep"), QStringLiteral("delay")})); 0176 QDBusPendingReply<QDBusUnixFileDescriptor> reply = m_bus.asyncCall(message); 0177 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); 0178 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) { 0179 QDBusPendingReply<QDBusUnixFileDescriptor> reply = *self; 0180 self->deleteLater(); 0181 if (!reply.isValid()) { 0182 return; 0183 } 0184 reply.value().swap(m_inhibitFileDescriptor); 0185 Q_EMIT inhibited(); 0186 }); 0187 } 0188 0189 void LogindIntegration::uninhibit() 0190 { 0191 if (!m_inhibitFileDescriptor.isValid()) { 0192 return; 0193 } 0194 m_inhibitFileDescriptor = QDBusUnixFileDescriptor(); 0195 } 0196 0197 bool LogindIntegration::isInhibited() const 0198 { 0199 return m_inhibitFileDescriptor.isValid(); 0200 } 0201 0202 void LogindIntegration::setLocked(bool locked) 0203 { 0204 if (!m_connected || m_sessionPath.isEmpty()) { 0205 return; 0206 } 0207 0208 QDBusMessage message = QDBusMessage::createMethodCall(*m_service, m_sessionPath, *m_sessionInterface, QStringLiteral("SetLockedHint")); 0209 message.setArguments({locked}); 0210 m_bus.call(message, QDBus::NoBlock); 0211 } 0212 0213 bool LogindIntegration::isLocked() const 0214 { 0215 if (!m_connected || m_sessionPath.isEmpty()) { 0216 return false; 0217 } 0218 0219 QDBusMessage message = QDBusMessage::createMethodCall(*m_service, m_sessionPath, s_propertyInterface, QStringLiteral("Get")); 0220 message.setArguments({*m_sessionInterface, QStringLiteral("LockedHint")}); 0221 QDBusReply<QDBusVariant> reply = m_bus.call(message); 0222 if (reply.isValid()) { 0223 return reply.value().variant().toBool(); 0224 } 0225 qCDebug(KSCREENLOCKER()) << reply.error(); 0226 return false; 0227 }