18 #include "dbusunitysessionservice.h" 21 #include <sys/types.h> 27 #include <QDBusPendingCall> 29 #include <QElapsedTimer> 31 #include <QDBusUnixFileDescriptor> 36 #define LOGIN1_SERVICE QStringLiteral("org.freedesktop.login1") 37 #define LOGIN1_PATH QStringLiteral("/org/freedesktop/login1") 38 #define LOGIN1_IFACE QStringLiteral("org.freedesktop.login1.Manager") 39 #define LOGIN1_SESSION_IFACE QStringLiteral("org.freedesktop.login1.Session") 41 #define ACTIVE_KEY QStringLiteral("Active") 42 #define IDLE_SINCE_KEY QStringLiteral("IdleSinceHint") 44 class DBusUnitySessionServicePrivate:
public QObject
48 QString logindSessionPath;
49 bool isSessionActive =
true;
50 QElapsedTimer screensaverActiveTimer;
51 QDBusUnixFileDescriptor m_systemdInhibitFd;
53 DBusUnitySessionServicePrivate(): QObject() {
61 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
64 QStringLiteral(
"GetSessionByPID"));
65 msg << (quint32) getpid();
67 QDBusReply<QDBusObjectPath> reply = QDBusConnection::SM_BUSNAME().call(msg);
68 if (reply.isValid()) {
69 logindSessionPath = reply.value().path();
72 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, logindSessionPath, QStringLiteral(
"org.freedesktop.DBus.Properties"), QStringLiteral(
"PropertiesChanged"),
73 this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
75 setupSystemdInhibition();
78 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, QStringLiteral(
"PrepareForSleep"),
79 this, SLOT(onResuming(
bool)));
81 qWarning() <<
"Failed to get logind session path" << reply.error().message();
85 void setupSystemdInhibition()
87 if (m_systemdInhibitFd.isValid())
93 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, QStringLiteral(
"Inhibit"));
94 msg <<
"handle-power-key:handle-suspend-key:handle-hibernate-key";
96 msg <<
"Unity8 handles power events";
99 QDBusPendingCall pendingCall = QDBusConnection::SM_BUSNAME().asyncCall(msg);
100 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
101 connect(watcher, &QDBusPendingCallWatcher::finished,
102 this, [
this](QDBusPendingCallWatcher* watcher) {
103 QDBusPendingReply<QDBusUnixFileDescriptor> reply = *watcher;
104 watcher->deleteLater();
105 if (reply.isError()) {
106 qWarning() <<
"Failed to inhibit systemd powersave handling" << reply.error().message();
110 m_systemdInhibitFd = reply.value();
114 bool checkLogin1Call(
const QString &method)
const 116 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, method);
117 QDBusReply<QString> reply = QDBusConnection::SM_BUSNAME().call(msg);
118 return reply.isValid() && (reply == QStringLiteral(
"yes") || reply == QStringLiteral(
"challenge"));
121 void makeLogin1Call(
const QString &method,
const QVariantList &args)
123 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
127 msg.setArguments(args);
128 QDBusConnection::SM_BUSNAME().asyncCall(msg);
131 void setActive(
bool active)
133 isSessionActive = active;
135 Q_EMIT screensaverActiveChanged(!isSessionActive);
137 if (isSessionActive) {
138 screensaverActiveTimer.invalidate();
141 screensaverActiveTimer.start();
148 if (logindSessionPath.isEmpty()) {
149 qWarning() <<
"Invalid session path";
153 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
155 QStringLiteral(
"org.freedesktop.DBus.Properties"),
156 QStringLiteral(
"Get"));
157 msg << LOGIN1_SESSION_IFACE;
160 QDBusPendingCall pendingCall = QDBusConnection::SM_BUSNAME().asyncCall(msg);
161 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
162 connect(watcher, &QDBusPendingCallWatcher::finished,
163 this, [
this](QDBusPendingCallWatcher* watcher) {
165 QDBusPendingReply<QVariant> reply = *watcher;
166 watcher->deleteLater();
167 if (reply.isError()) {
168 qWarning() <<
"Failed to get Active property" << reply.error().message();
172 setActive(reply.value().toBool());
176 quint32 screensaverActiveTime()
const 178 if (!isSessionActive && screensaverActiveTimer.isValid()) {
179 return screensaverActiveTimer.elapsed() / 1000;
185 quint64 idleSinceUSecTimestamp()
const 187 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
189 QStringLiteral(
"org.freedesktop.DBus.Properties"),
190 QStringLiteral(
"Get"));
191 msg << LOGIN1_SESSION_IFACE;
192 msg << IDLE_SINCE_KEY;
194 QDBusReply<QVariant> reply = QDBusConnection::SM_BUSNAME().call(msg);
195 if (reply.isValid()) {
196 return reply.value().value<quint64>();
198 qWarning() <<
"Failed to get IdleSinceHint property" << reply.error().message();
204 void setIdleHint(
bool idle)
206 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
208 LOGIN1_SESSION_IFACE,
209 QStringLiteral(
"SetIdleHint"));
211 QDBusConnection::SM_BUSNAME().asyncCall(msg);
215 void onPropertiesChanged(
const QString &iface,
const QVariantMap &changedProps,
const QStringList &invalidatedProps)
219 if (changedProps.contains(ACTIVE_KEY)) {
220 setActive(changedProps.value(ACTIVE_KEY).toBool());
221 }
else if (invalidatedProps.contains(ACTIVE_KEY)) {
226 void onResuming(
bool active)
229 setupSystemdInhibition();
231 Q_EMIT prepareForSleep();
236 void screensaverActiveChanged(
bool active);
237 void prepareForSleep();
240 Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
243 : UnityDBusObject(QStringLiteral("/
com/canonical/Unity/Session"), QStringLiteral("
com.canonical.Unity"))
245 if (!d->logindSessionPath.isEmpty()) {
247 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Lock"),
this, SLOT(PromptLock()));
250 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Unlock"),
this, SLOT(doUnlock()));
253 qWarning() <<
"Failed to connect to logind's session Lock/Unlock signals";
260 Q_EMIT LogoutReady();
261 Q_EMIT logoutReady();
266 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.ubuntu.Upstart"),
267 QStringLiteral(
"/com/ubuntu/Upstart"),
268 QStringLiteral(
"com.ubuntu.Upstart0_6"),
269 QStringLiteral(
"EndSession"));
270 QDBusConnection::sessionBus().asyncCall(msg);
275 return d->checkLogin1Call(QStringLiteral(
"CanHibernate"));
280 return d->checkLogin1Call(QStringLiteral(
"CanSuspend"));
285 return d->checkLogin1Call(QStringLiteral(
"CanHybridSleep"));
290 return d->checkLogin1Call(QStringLiteral(
"CanReboot"));
295 return d->checkLogin1Call(QStringLiteral(
"CanPowerOff"));
305 return QString::fromUtf8(g_get_user_name());
310 struct passwd *p = getpwuid(geteuid());
312 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
313 if (!gecos.isEmpty()) {
314 const QStringList splitGecos = gecos.split(QLatin1Char(
','));
315 return splitGecos.first();
325 if (gethostname(hostName,
sizeof(hostName)) == -1) {
326 qWarning() <<
"Could not determine local hostname";
329 hostName[
sizeof(hostName) - 1] =
'\0';
330 return QString::fromLocal8Bit(hostName);
338 Q_EMIT LockRequested();
339 Q_EMIT lockRequested();
368 void DBusUnitySessionService::switchToGreeter()
371 const QString sessionPath = QString::fromLocal8Bit(qgetenv(
"XDG_SESSION_PATH"));
372 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"org.freedesktop.DisplayManager"),
374 QStringLiteral(
"org.freedesktop.DisplayManager.Session"),
375 QStringLiteral(
"Lock"));
377 QDBusPendingCall pendingCall = QDBusConnection::SM_BUSNAME().asyncCall(msg);
378 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
379 connect(watcher, &QDBusPendingCallWatcher::finished,
380 this, [
this](QDBusPendingCallWatcher* watcher) {
382 QDBusPendingReply<void> reply = *watcher;
383 watcher->deleteLater();
384 if (reply.isError()) {
385 qWarning() <<
"Lock call failed" << reply.error().message();
394 void DBusUnitySessionService::doUnlock()
402 return !d->isSessionActive;
407 Q_EMIT LogoutRequested(
false);
408 Q_EMIT logoutRequested(
false);
413 d->makeLogin1Call(QStringLiteral(
"Reboot"), {
false});
418 Q_EMIT RebootRequested(
false);
419 Q_EMIT rebootRequested(
false);
424 d->makeLogin1Call(QStringLiteral(
"PowerOff"), {
false});
430 d->makeLogin1Call(QStringLiteral(
"Suspend"), {
false});
436 d->makeLogin1Call(QStringLiteral(
"Hibernate"), {
false});
442 d->makeLogin1Call(QStringLiteral(
"HybridSleep"), {
false});
447 Q_EMIT ShutdownRequested(
false);
448 Q_EMIT shutdownRequested(
false);
451 enum class Action : unsigned
460 void performAsyncUnityCall(
const QString &method)
462 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.canonical.Unity"),
463 QStringLiteral(
"/com/canonical/Unity/Session"),
464 QStringLiteral(
"com.canonical.Unity.Session"),
466 QDBusConnection::sessionBus().asyncCall(msg);
470 DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
471 : UnityDBusObject(QStringLiteral(
"/org/gnome/SessionManager/EndSessionDialog"), QStringLiteral(
"com.canonical.Unity"))
475 void DBusGnomeSessionManagerWrapper::Open(
const unsigned type,
const unsigned arg_1,
const unsigned max_wait,
const QList<QDBusObjectPath> &inhibitors)
479 Q_UNUSED(inhibitors);
481 switch (static_cast<Action>(type))
484 performAsyncUnityCall(QStringLiteral(
"RequestLogout"));
488 performAsyncUnityCall(QStringLiteral(
"RequestReboot"));
491 case Action::SHUTDOWN:
492 performAsyncUnityCall(QStringLiteral(
"RequestShutdown"));
501 DBusGnomeScreensaverWrapper::DBusGnomeScreensaverWrapper()
502 : UnityDBusObject(QStringLiteral(
"/org/gnome/ScreenSaver"), QStringLiteral(
"org.gnome.ScreenSaver"))
504 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusGnomeScreensaverWrapper::ActiveChanged);
507 bool DBusGnomeScreensaverWrapper::GetActive()
const 509 return !d->isSessionActive;
512 void DBusGnomeScreensaverWrapper::SetActive(
bool lock)
519 void DBusGnomeScreensaverWrapper::Lock()
521 performAsyncUnityCall(QStringLiteral(
"PromptLock"));
524 quint32 DBusGnomeScreensaverWrapper::GetActiveTime()
const 526 return d->screensaverActiveTime();
529 void DBusGnomeScreensaverWrapper::SimulateUserActivity()
531 d->setIdleHint(
false);
535 DBusScreensaverWrapper::DBusScreensaverWrapper()
536 : UnityDBusObject(QStringLiteral(
"/org/freedesktop/ScreenSaver"), QStringLiteral(
"org.freedesktop.ScreenSaver"))
538 QDBusConnection::sessionBus().registerObject(QStringLiteral(
"/ScreenSaver"),
this, QDBusConnection::ExportScriptableContents);
539 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusScreensaverWrapper::ActiveChanged);
542 bool DBusScreensaverWrapper::GetActive()
const 544 return !d->isSessionActive;
547 bool DBusScreensaverWrapper::SetActive(
bool lock)
556 void DBusScreensaverWrapper::Lock()
558 performAsyncUnityCall(QStringLiteral(
"PromptLock"));
561 quint32 DBusScreensaverWrapper::GetActiveTime()
const 563 return d->screensaverActiveTime();
566 quint32 DBusScreensaverWrapper::GetSessionIdleTime()
const 568 return QDateTime::fromMSecsSinceEpoch(d->idleSinceUSecTimestamp()/1000).secsTo(QDateTime::currentDateTime());
571 void DBusScreensaverWrapper::SimulateUserActivity()
573 d->setIdleHint(
false);
576 #include "dbusunitysessionservice.moc" Q_SCRIPTABLE bool CanShutdown() const
Q_SCRIPTABLE void Reboot()
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 Hibernate()
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 bool CanReboot() const
Q_SCRIPTABLE void Suspend()
Q_SCRIPTABLE QString HostName() const
Q_SCRIPTABLE bool CanHybridSleep() const
Q_SCRIPTABLE void EndSession()
Q_SCRIPTABLE void Logout()