10#include <QCoreApplication>
11#include <QDBusConnection>
12#include <QDBusConnectionInterface>
13#include <QDBusInterface>
14#include <QDBusMessage>
15#include <QDBusMetaType>
16#include <QDBusObjectPath>
17#include <QDBusPendingCall>
18#include <QDBusUnixFileDescriptor>
24#if __has_include(<sys/sysmacros.h>)
25#include <sys/sysmacros.h>
36 argument.beginStructure();
37 argument << seat.id << seat.path;
38 argument.endStructure();
44 argument.beginStructure();
45 argument >> seat.id >> seat.path;
46 argument.endStructure();
55static const QString s_serviceName = QStringLiteral(
"org.freedesktop.login1");
56static const QString s_propertiesInterface = QStringLiteral(
"org.freedesktop.DBus.Properties");
57static const QString s_sessionInterface = QStringLiteral(
"org.freedesktop.login1.Session");
58static const QString s_seatInterface = QStringLiteral(
"org.freedesktop.login1.Seat");
59static const QString s_managerInterface = QStringLiteral(
"org.freedesktop.login1.Manager");
60static const QString s_managerPath = QStringLiteral(
"/org/freedesktop/login1");
62static QString findProcessSessionPath()
64 const QString sessionId = qEnvironmentVariable(
"XDG_SESSION_ID", QStringLiteral(
"auto"));
65 QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, s_managerPath,
67 QStringLiteral(
"GetSession"));
68 message.setArguments({sessionId});
69 const QDBusMessage reply = QDBusConnection::systemBus().call(message);
70 if (reply.type() == QDBusMessage::ErrorMessage) {
74 return reply.arguments().constFirst().value<QDBusObjectPath>().path();
77static bool takeControl(
const QString &sessionPath)
79 QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, sessionPath,
81 QStringLiteral(
"TakeControl"));
82 message.setArguments({
false});
84 const QDBusMessage reply = QDBusConnection::systemBus().call(message);
86 return reply.type() != QDBusMessage::ErrorMessage;
89static void releaseControl(
const QString &sessionPath)
91 const QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, sessionPath,
93 QStringLiteral(
"ReleaseControl"));
95 QDBusConnection::systemBus().asyncCall(message);
98static bool activate(
const QString &sessionPath)
100 const QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, sessionPath,
102 QStringLiteral(
"Activate"));
104 const QDBusMessage reply = QDBusConnection::systemBus().call(message);
106 return reply.type() != QDBusMessage::ErrorMessage;
111 if (!QDBusConnection::systemBus().interface()->isServiceRegistered(s_serviceName)) {
115 const QString sessionPath = findProcessSessionPath();
116 if (sessionPath.isEmpty()) {
117 qCWarning(KWIN_CORE) <<
"Could not determine the active graphical session";
121 if (!activate(sessionPath)) {
122 qCWarning(KWIN_CORE,
"Failed to activate %s session. Maybe another compositor is running?",
123 qPrintable(sessionPath));
127 if (!takeControl(sessionPath)) {
128 qCWarning(KWIN_CORE,
"Failed to take control of %s session. Maybe another compositor is running?",
129 qPrintable(sessionPath));
133 std::unique_ptr<LogindSession> session{
new LogindSession(sessionPath)};
134 if (session->initialize()) {
164 if (stat(fileName.toUtf8(), &st) < 0) {
168 QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, m_sessionPath,
170 QStringLiteral(
"TakeDevice"));
172 message.setArguments({uint(major(st.st_rdev)), uint(minor(st.st_rdev))});
174 const QDBusMessage reply = QDBusConnection::systemBus().call(message);
175 if (reply.type() == QDBusMessage::ErrorMessage) {
176 qCWarning(KWIN_CORE,
"Failed to open %s device (%s)",
177 qPrintable(fileName), qPrintable(reply.errorMessage()));
181 const QDBusUnixFileDescriptor descriptor = reply.arguments().constFirst().value<QDBusUnixFileDescriptor>();
182 if (!descriptor.isValid()) {
183 qCWarning(KWIN_CORE,
"File descriptor for %s from logind is invalid", qPrintable(fileName));
187 return fcntl(descriptor.fileDescriptor(), F_DUPFD_CLOEXEC, 0);
193 if (fstat(fileDescriptor, &st) < 0) {
194 close(fileDescriptor);
198 QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, m_sessionPath,
200 QStringLiteral(
"ReleaseDevice"));
202 message.setArguments({uint(major(st.st_rdev)), uint(minor(st.st_rdev))});
204 QDBusConnection::systemBus().asyncCall(message);
206 close(fileDescriptor);
211 QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, m_seatPath,
213 QStringLiteral(
"SwitchTo"));
216 QDBusConnection::systemBus().asyncCall(message);
219LogindSession::LogindSession(
const QString &sessionPath)
220 : m_sessionPath(sessionPath)
222 qDBusRegisterMetaType<DBusLogindSeat>();
227 releaseControl(m_sessionPath);
230bool LogindSession::initialize()
232 QDBusMessage activeMessage = QDBusMessage::createMethodCall(s_serviceName, m_sessionPath,
233 s_propertiesInterface,
234 QStringLiteral(
"Get"));
235 activeMessage.setArguments({s_sessionInterface, QStringLiteral(
"Active")});
237 QDBusMessage seatMessage = QDBusMessage::createMethodCall(s_serviceName, m_sessionPath,
238 s_propertiesInterface,
239 QStringLiteral(
"Get"));
240 seatMessage.setArguments({s_sessionInterface, QStringLiteral(
"Seat")});
242 QDBusMessage terminalMessage = QDBusMessage::createMethodCall(s_serviceName, m_sessionPath,
243 s_propertiesInterface,
244 QStringLiteral(
"Get"));
245 terminalMessage.setArguments({s_sessionInterface, QStringLiteral(
"VTNr")});
247 QDBusPendingReply<QVariant> activeReply =
248 QDBusConnection::systemBus().asyncCall(activeMessage);
249 QDBusPendingReply<QVariant> terminalReply =
250 QDBusConnection::systemBus().asyncCall(terminalMessage);
251 QDBusPendingReply<QVariant> seatReply =
252 QDBusConnection::systemBus().asyncCall(seatMessage);
256 activeReply.waitForFinished();
257 terminalReply.waitForFinished();
258 seatReply.waitForFinished();
260 if (activeReply.isError()) {
261 qCWarning(KWIN_CORE) <<
"Failed to query Active session property:" << activeReply.error();
264 if (terminalReply.isError()) {
265 qCWarning(KWIN_CORE) <<
"Failed to query VTNr session property:" << terminalReply.error();
268 if (seatReply.isError()) {
269 qCWarning(KWIN_CORE) <<
"Failed to query Seat session property:" << seatReply.error();
273 m_isActive = activeReply.value().toBool();
274 m_terminal = terminalReply.value().toUInt();
276 const DBusLogindSeat seat = qdbus_cast<DBusLogindSeat>(seatReply.value().value<QDBusArgument>());
278 m_seatPath =
seat.path.path();
280 QDBusConnection::systemBus().connect(s_serviceName, s_managerPath, s_managerInterface,
281 QStringLiteral(
"PrepareForSleep"),
283 SLOT(handlePrepareForSleep(
bool)));
285 QDBusConnection::systemBus().connect(s_serviceName, m_sessionPath, s_sessionInterface,
286 QStringLiteral(
"PauseDevice"),
288 SLOT(handlePauseDevice(uint, uint, QString)));
290 QDBusConnection::systemBus().connect(s_serviceName, m_sessionPath, s_sessionInterface,
291 QStringLiteral(
"ResumeDevice"),
293 SLOT(handleResumeDevice(uint, uint, QDBusUnixFileDescriptor)));
295 QDBusConnection::systemBus().connect(s_serviceName, m_sessionPath, s_propertiesInterface,
296 QStringLiteral(
"PropertiesChanged"),
298 SLOT(handlePropertiesChanged(QString, QVariantMap)));
303void LogindSession::updateActive(
bool active)
305 if (m_isActive != active) {
311void LogindSession::handlePauseDevice(uint major, uint minor,
const QString &
type)
315 if (
type == QLatin1String(
"pause")) {
316 QDBusMessage message = QDBusMessage::createMethodCall(s_serviceName, m_sessionPath,
318 QStringLiteral(
"PauseDeviceComplete"));
319 message.setArguments({major, minor});
321 QDBusConnection::systemBus().asyncCall(message);
325void LogindSession::handleResumeDevice(uint major, uint minor, QDBusUnixFileDescriptor fileDescriptor)
333void LogindSession::handlePropertiesChanged(
const QString &interfaceName,
const QVariantMap &properties)
335 if (interfaceName == s_sessionInterface) {
336 const QVariant active = properties.value(QStringLiteral(
"Active"));
337 if (active.isValid()) {
338 updateActive(active.toBool());
343void LogindSession::handlePrepareForSleep(
bool sleep)
352#include "moc_session_logind.cpp"
int openRestricted(const QString &fileName) override
uint terminal() const override
~LogindSession() override
bool isActive() const override
void closeRestricted(int fileDescriptor) override
Capabilities capabilities() const override
QString seat() const override
static std::unique_ptr< LogindSession > create()
void switchTo(uint terminal) override
void activeChanged(bool active)
void devicePaused(dev_t deviceId)
void deviceResumed(dev_t deviceId)
const QDBusArgument & operator>>(const QDBusArgument &argument, DBusLogindSeat &seat)
QDBusArgument & operator<<(QDBusArgument &argument, const DBusLogindSeat &seat)