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