18 #include "dbusunitysessionservice.h"
21 #include <sys/types.h>
27 #include <QDBusPendingCall>
29 #include <QElapsedTimer>
31 #include <QDBusUnixFileDescriptor>
33 #define LOGIN1_SERVICE QStringLiteral("org.freedesktop.login1")
34 #define LOGIN1_PATH QStringLiteral("/org/freedesktop/login1")
35 #define LOGIN1_IFACE QStringLiteral("org.freedesktop.login1.Manager")
36 #define LOGIN1_SESSION_IFACE QStringLiteral("org.freedesktop.login1.Session")
38 #define ACTIVE_KEY QStringLiteral("Active")
39 #define IDLE_SINCE_KEY QStringLiteral("IdleSinceHint")
41 class DBusUnitySessionServicePrivate:
public QObject
45 QString logindSessionPath;
46 bool isSessionActive =
true;
47 QElapsedTimer screensaverActiveTimer;
48 QDBusUnixFileDescriptor m_systemdInhibitFd;
50 DBusUnitySessionServicePrivate(): QObject() {
58 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
61 QStringLiteral(
"GetSessionByPID"));
62 msg << (quint32) getpid();
64 QDBusReply<QDBusObjectPath> reply = QDBusConnection::systemBus().asyncCall(msg);
65 if (reply.isValid()) {
66 logindSessionPath = reply.value().path();
69 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, logindSessionPath, QStringLiteral(
"org.freedesktop.DBus.Properties"), QStringLiteral(
"PropertiesChanged"),
70 this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
72 setupSystemdInhibition();
75 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, QStringLiteral(
"PrepareForSleep"),
76 this, SLOT(onResuming(
bool)));
78 qWarning() <<
"Failed to get logind session path" << reply.error().message();
82 void setupSystemdInhibition()
84 if (m_systemdInhibitFd.isValid())
90 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, QStringLiteral(
"Inhibit"));
91 msg <<
"handle-power-key:handle-suspend-key:handle-hibernate-key:handle-lid-switch";
93 msg <<
"Unity8 handles power events";
95 QDBusReply<QDBusUnixFileDescriptor> desc = QDBusConnection::systemBus().asyncCall(msg);
98 m_systemdInhibitFd = desc.value();
100 qWarning() <<
"failed to inhibit systemd powersave handling";
105 bool checkLogin1Call(
const QString &method)
const
107 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, method);
108 QDBusReply<QString> reply = QDBusConnection::systemBus().asyncCall(msg);
109 return reply.isValid() && (reply == QStringLiteral(
"yes") || reply == QStringLiteral(
"challenge"));
112 void makeLogin1Call(
const QString &method,
const QVariantList &args)
114 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
118 msg.setArguments(args);
119 QDBusConnection::systemBus().asyncCall(msg);
124 if (logindSessionPath.isEmpty()) {
125 qWarning() <<
"Invalid session path";
129 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
131 QStringLiteral(
"org.freedesktop.DBus.Properties"),
132 QStringLiteral(
"Get"));
133 msg << LOGIN1_SESSION_IFACE;
136 QDBusReply<QVariant> reply = QDBusConnection::systemBus().asyncCall(msg);
137 if (reply.isValid()) {
138 isSessionActive = reply.value().toBool();
140 qWarning() <<
"Failed to get Active property" << reply.error().message();
144 quint32 screensaverActiveTime()
const
146 if (!isSessionActive && screensaverActiveTimer.isValid()) {
147 return screensaverActiveTimer.elapsed() / 1000;
153 quint64 idleSinceUSecTimestamp()
const
155 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
157 QStringLiteral(
"org.freedesktop.DBus.Properties"),
158 QStringLiteral(
"Get"));
159 msg << LOGIN1_SESSION_IFACE;
160 msg << IDLE_SINCE_KEY;
162 QDBusReply<QVariant> reply = QDBusConnection::systemBus().asyncCall(msg);
163 if (reply.isValid()) {
164 return reply.value().value<quint64>();
166 qWarning() <<
"Failed to get IdleSinceHint property" << reply.error().message();
172 void setIdleHint(
bool idle)
174 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
176 LOGIN1_SESSION_IFACE,
177 QStringLiteral(
"SetIdleHint"));
179 QDBusConnection::systemBus().asyncCall(msg);
183 void onPropertiesChanged(
const QString &iface,
const QVariantMap &changedProps,
const QStringList &invalidatedProps)
187 if (changedProps.contains(ACTIVE_KEY) || invalidatedProps.contains(ACTIVE_KEY)) {
188 if (changedProps.value(ACTIVE_KEY).isValid()) {
189 isSessionActive = changedProps.value(ACTIVE_KEY).toBool();
194 Q_EMIT screensaverActiveChanged(!isSessionActive);
196 if (isSessionActive) {
197 screensaverActiveTimer.invalidate();
200 screensaverActiveTimer.start();
206 void onResuming(
bool active)
209 setupSystemdInhibition();
214 void screensaverActiveChanged(
bool active);
217 Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
220 : UnityDBusObject(QStringLiteral("/
com/canonical/Unity/Session"), QStringLiteral("
com.canonical.Unity"))
222 if (!d->logindSessionPath.isEmpty()) {
224 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Lock"),
this, SLOT(Lock()));
227 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Unlock"),
this, SIGNAL(Unlocked()));
229 qWarning() <<
"Failed to connect to logind's session Lock/Unlock signals";
237 Q_EMIT logoutReady();
242 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.ubuntu.Upstart"),
243 QStringLiteral(
"/com/ubuntu/Upstart"),
244 QStringLiteral(
"com.ubuntu.Upstart0_6"),
245 QStringLiteral(
"EndSession"));
246 QDBusConnection::sessionBus().asyncCall(msg);
251 return d->checkLogin1Call(QStringLiteral(
"CanHibernate"));
256 return d->checkLogin1Call(QStringLiteral(
"CanSuspend"));
261 return d->checkLogin1Call(QStringLiteral(
"CanHybridSleep"));
266 return d->checkLogin1Call(QStringLiteral(
"CanReboot"));
271 return d->checkLogin1Call(QStringLiteral(
"CanPowerOff"));
281 struct passwd *p = getpwuid(geteuid());
283 return QString::fromUtf8(p->pw_name);
291 struct passwd *p = getpwuid(geteuid());
293 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
294 if (!gecos.isEmpty()) {
295 const QStringList splitGecos = gecos.split(QLatin1Char(
','));
296 return splitGecos.first();
306 if (gethostname(hostName,
sizeof(hostName)) == -1) {
307 qWarning() <<
"Could not determine local hostname";
310 hostName[
sizeof(hostName) - 1] =
'\0';
311 return QString::fromLocal8Bit(hostName);
317 Q_EMIT lockRequested();
323 const QString sessionPath = QString::fromLocal8Bit(qgetenv(
"XDG_SESSION_PATH"));
324 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"org.freedesktop.DisplayManager"),
326 QStringLiteral(
"org.freedesktop.DisplayManager.Session"),
327 QStringLiteral(
"Lock"));
328 QDBusReply<void> reply = QDBusConnection::systemBus().asyncCall(msg);
329 if (!reply.isValid()) {
330 qWarning() <<
"Lock call failed" << reply.error().message();
339 return !d->isSessionActive;
345 Q_EMIT logoutRequested(
false);
350 d->makeLogin1Call(QStringLiteral(
"Reboot"), {
false});
356 Q_EMIT rebootRequested(
false);
361 d->makeLogin1Call(QStringLiteral(
"PowerOff"), {
false});
366 d->makeLogin1Call(QStringLiteral(
"Suspend"), {
false});
371 d->makeLogin1Call(QStringLiteral(
"Hibernate"), {
false});
376 d->makeLogin1Call(QStringLiteral(
"HybridSleep"), {
false});
382 Q_EMIT shutdownRequested(
false);
385 enum class Action : unsigned
394 void performAsyncUnityCall(
const QString &method)
396 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.canonical.Unity"),
397 QStringLiteral(
"/com/canonical/Unity/Session"),
398 QStringLiteral(
"com.canonical.Unity.Session"),
400 QDBusConnection::sessionBus().asyncCall(msg);
404 DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
405 : UnityDBusObject(QStringLiteral(
"/org/gnome/SessionManager/EndSessionDialog"), QStringLiteral(
"com.canonical.Unity"))
409 void DBusGnomeSessionManagerWrapper::Open(
const unsigned type,
const unsigned arg_1,
const unsigned max_wait,
const QList<QDBusObjectPath> &inhibitors)
413 Q_UNUSED(inhibitors);
415 switch (static_cast<Action>(type))
418 performAsyncUnityCall(QStringLiteral(
"RequestLogout"));
422 performAsyncUnityCall(QStringLiteral(
"RequestReboot"));
425 case Action::SHUTDOWN:
426 performAsyncUnityCall(QStringLiteral(
"RequestShutdown"));
435 DBusGnomeScreensaverWrapper::DBusGnomeScreensaverWrapper()
436 : UnityDBusObject(QStringLiteral(
"/org/gnome/ScreenSaver"), QStringLiteral(
"org.gnome.ScreenSaver"))
438 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusGnomeScreensaverWrapper::ActiveChanged);
441 bool DBusGnomeScreensaverWrapper::GetActive()
const
443 return !d->isSessionActive;
446 void DBusGnomeScreensaverWrapper::SetActive(
bool lock)
453 void DBusGnomeScreensaverWrapper::Lock()
455 performAsyncUnityCall(QStringLiteral(
"Lock"));
458 quint32 DBusGnomeScreensaverWrapper::GetActiveTime()
const
460 return d->screensaverActiveTime();
463 void DBusGnomeScreensaverWrapper::SimulateUserActivity()
465 d->setIdleHint(
false);
469 DBusScreensaverWrapper::DBusScreensaverWrapper()
470 : UnityDBusObject(QStringLiteral(
"/org/freedesktop/ScreenSaver"), QStringLiteral(
"org.freedesktop.ScreenSaver"))
472 QDBusConnection::sessionBus().registerObject(QStringLiteral(
"/ScreenSaver"),
this, QDBusConnection::ExportScriptableContents);
473 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusScreensaverWrapper::ActiveChanged);
476 bool DBusScreensaverWrapper::GetActive()
const
478 return !d->isSessionActive;
481 bool DBusScreensaverWrapper::SetActive(
bool lock)
490 void DBusScreensaverWrapper::Lock()
492 performAsyncUnityCall(QStringLiteral(
"Lock"));
495 quint32 DBusScreensaverWrapper::GetActiveTime()
const
497 return d->screensaverActiveTime();
500 quint32 DBusScreensaverWrapper::GetSessionIdleTime()
const
502 return QDateTime::fromMSecsSinceEpoch(d->idleSinceUSecTimestamp()/1000).secsTo(QDateTime::currentDateTime());
505 void DBusScreensaverWrapper::SimulateUserActivity()
507 d->setIdleHint(
false);
510 #include "dbusunitysessionservice.moc"
Q_SCRIPTABLE void LogoutReady()
Q_SCRIPTABLE bool CanShutdown() const
Q_SCRIPTABLE void Reboot()
Q_SCRIPTABLE void RebootRequested(bool have_inhibitors)
Q_SCRIPTABLE void RequestLogout()
Q_SCRIPTABLE QString RealName() const
Q_SCRIPTABLE bool CanLock() const
Q_SCRIPTABLE void RequestReboot()
Q_SCRIPTABLE void RequestShutdown()
Q_SCRIPTABLE void HybridSleep()
Q_SCRIPTABLE bool CanHibernate() const
Q_SCRIPTABLE void ShutdownRequested(bool have_inhibitors)
Q_SCRIPTABLE void Hibernate()
Q_SCRIPTABLE void Locked()
Q_SCRIPTABLE QString UserName() const
Q_SCRIPTABLE bool CanSuspend() const
Q_SCRIPTABLE bool IsLocked() const
Q_SCRIPTABLE void Shutdown()
Q_SCRIPTABLE void PromptLock()
Q_SCRIPTABLE void LogoutRequested(bool have_inhibitors)
Q_SCRIPTABLE bool CanReboot() const
Q_SCRIPTABLE void Suspend()
Q_SCRIPTABLE void LockRequested()
Q_SCRIPTABLE QString HostName() const
Q_SCRIPTABLE bool CanHybridSleep() const
Q_SCRIPTABLE void EndSession()
Q_SCRIPTABLE void Logout()