18 #include "dbusunitysessionservice.h" 22 #include <sys/types.h> 28 #include <QDBusPendingCall> 30 #include <QElapsedTimer> 32 #include <QDBusUnixFileDescriptor> 37 #define LOGIN1_SERVICE QStringLiteral("org.freedesktop.login1") 38 #define LOGIN1_PATH QStringLiteral("/org/freedesktop/login1") 39 #define LOGIN1_IFACE QStringLiteral("org.freedesktop.login1.Manager") 40 #define LOGIN1_SESSION_IFACE QStringLiteral("org.freedesktop.login1.Session") 42 #define ACTIVE_KEY QStringLiteral("Active") 43 #define IDLE_SINCE_KEY QStringLiteral("IdleSinceHint") 45 class DBusUnitySessionServicePrivate:
public QObject
49 QString logindSessionPath;
50 bool isSessionActive =
true;
51 QElapsedTimer screensaverActiveTimer;
52 QDBusUnixFileDescriptor m_systemdInhibitFd;
54 DBusUnitySessionServicePrivate(): QObject() {
62 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
65 QStringLiteral(
"GetSessionByPID"));
66 msg << (quint32) getpid();
68 QDBusReply<QDBusObjectPath> reply = QDBusConnection::SM_BUSNAME().call(msg);
69 if (reply.isValid()) {
70 logindSessionPath = reply.value().path();
73 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, logindSessionPath, QStringLiteral(
"org.freedesktop.DBus.Properties"), QStringLiteral(
"PropertiesChanged"),
74 this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
76 setupSystemdInhibition();
79 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, QStringLiteral(
"PrepareForSleep"),
80 this, SLOT(onResuming(
bool)));
82 qWarning() <<
"Failed to get logind session path" << reply.error().message();
86 void setupSystemdInhibition()
88 if (m_systemdInhibitFd.isValid())
94 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, QStringLiteral(
"Inhibit"));
95 msg <<
"handle-power-key:handle-suspend-key:handle-hibernate-key";
97 msg <<
"Unity8 handles power events";
100 QDBusPendingCall pendingCall = QDBusConnection::SM_BUSNAME().asyncCall(msg);
101 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
102 connect(watcher, &QDBusPendingCallWatcher::finished,
103 this, [
this](QDBusPendingCallWatcher* watcher) {
104 QDBusPendingReply<QDBusUnixFileDescriptor> reply = *watcher;
105 watcher->deleteLater();
106 if (reply.isError()) {
107 qWarning() <<
"Failed to inhibit systemd powersave handling" << reply.error().message();
111 m_systemdInhibitFd = reply.value();
115 bool checkLogin1Call(
const QString &method)
const 117 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, method);
118 QDBusReply<QString> reply = QDBusConnection::SM_BUSNAME().call(msg);
119 return reply.isValid() && (reply == QStringLiteral(
"yes") || reply == QStringLiteral(
"challenge"));
122 void makeLogin1Call(
const QString &method,
const QVariantList &args)
124 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
128 msg.setArguments(args);
129 QDBusConnection::SM_BUSNAME().asyncCall(msg);
132 void setActive(
bool active)
134 isSessionActive = active;
136 Q_EMIT screensaverActiveChanged(!isSessionActive);
138 if (isSessionActive) {
139 screensaverActiveTimer.invalidate();
142 screensaverActiveTimer.start();
149 if (logindSessionPath.isEmpty()) {
150 qWarning() <<
"Invalid session path";
154 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
156 QStringLiteral(
"org.freedesktop.DBus.Properties"),
157 QStringLiteral(
"Get"));
158 msg << LOGIN1_SESSION_IFACE;
161 QDBusPendingCall pendingCall = QDBusConnection::SM_BUSNAME().asyncCall(msg);
162 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
163 connect(watcher, &QDBusPendingCallWatcher::finished,
164 this, [
this](QDBusPendingCallWatcher* watcher) {
166 QDBusPendingReply<QVariant> reply = *watcher;
167 watcher->deleteLater();
168 if (reply.isError()) {
169 qWarning() <<
"Failed to get Active property" << reply.error().message();
173 setActive(reply.value().toBool());
177 quint32 screensaverActiveTime()
const 179 if (!isSessionActive && screensaverActiveTimer.isValid()) {
180 return screensaverActiveTimer.elapsed() / 1000;
186 quint64 idleSinceUSecTimestamp()
const 188 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
190 QStringLiteral(
"org.freedesktop.DBus.Properties"),
191 QStringLiteral(
"Get"));
192 msg << LOGIN1_SESSION_IFACE;
193 msg << IDLE_SINCE_KEY;
195 QDBusReply<QVariant> reply = QDBusConnection::SM_BUSNAME().call(msg);
196 if (reply.isValid()) {
197 return reply.value().value<quint64>();
199 qWarning() <<
"Failed to get IdleSinceHint property" << reply.error().message();
205 void setIdleHint(
bool idle)
207 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
209 LOGIN1_SESSION_IFACE,
210 QStringLiteral(
"SetIdleHint"));
212 QDBusConnection::SM_BUSNAME().asyncCall(msg);
215 bool isUserInGroup(
const QString &user,
const QString &groupName)
const 217 auto group = getgrnam(groupName.toUtf8().data());
219 if (group && group->gr_mem)
221 for (
int i = 0; group->gr_mem[i]; ++i)
223 if (g_strcmp0(group->gr_mem[i], user.toUtf8().data()) == 0) {
233 void onPropertiesChanged(
const QString &iface,
const QVariantMap &changedProps,
const QStringList &invalidatedProps)
237 if (changedProps.contains(ACTIVE_KEY)) {
238 setActive(changedProps.value(ACTIVE_KEY).toBool());
239 }
else if (invalidatedProps.contains(ACTIVE_KEY)) {
244 void onResuming(
bool active)
247 setupSystemdInhibition();
249 Q_EMIT prepareForSleep();
254 void screensaverActiveChanged(
bool active);
255 void prepareForSleep();
258 Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
260 DBusUnitySessionService::DBusUnitySessionService()
261 : UnityDBusObject(QStringLiteral(
"/com/canonical/Unity/Session"), QStringLiteral(
"com.canonical.Unity"))
263 if (!d->logindSessionPath.isEmpty()) {
265 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Lock"),
this, SLOT(PromptLock()));
268 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Unlock"),
this, SLOT(doUnlock()));
271 qWarning() <<
"Failed to connect to logind's session Lock/Unlock signals";
278 Q_EMIT LogoutReady();
279 Q_EMIT logoutReady();
284 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.ubuntu.Upstart"),
285 QStringLiteral(
"/com/ubuntu/Upstart"),
286 QStringLiteral(
"com.ubuntu.Upstart0_6"),
287 QStringLiteral(
"EndSession"));
288 QDBusConnection::sessionBus().asyncCall(msg);
293 return d->checkLogin1Call(QStringLiteral(
"CanHibernate"));
298 return d->checkLogin1Call(QStringLiteral(
"CanSuspend"));
303 return d->checkLogin1Call(QStringLiteral(
"CanHybridSleep"));
308 return d->checkLogin1Call(QStringLiteral(
"CanReboot"));
313 return d->checkLogin1Call(QStringLiteral(
"CanPowerOff"));
318 auto user = UserName();
319 if (user.startsWith(QStringLiteral(
"guest-")) ||
320 d->isUserInGroup(user, QStringLiteral(
"nopasswdlogin"))) {
329 return QString::fromUtf8(g_get_user_name());
334 struct passwd *p = getpwuid(geteuid());
336 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
337 if (!gecos.isEmpty()) {
338 const QStringList splitGecos = gecos.split(QLatin1Char(
','));
339 return splitGecos.first();
349 if (gethostname(hostName,
sizeof(hostName)) == -1) {
350 qWarning() <<
"Could not determine local hostname";
353 hostName[
sizeof(hostName) - 1] =
'\0';
354 return QString::fromLocal8Bit(hostName);
363 Q_EMIT LockRequested();
364 Q_EMIT lockRequested();
394 void DBusUnitySessionService::switchToGreeter()
397 const QString sessionPath = QString::fromLocal8Bit(qgetenv(
"XDG_SESSION_PATH"));
398 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"org.freedesktop.DisplayManager"),
400 QStringLiteral(
"org.freedesktop.DisplayManager.Session"),
401 QStringLiteral(
"Lock"));
403 QDBusPendingCall pendingCall = QDBusConnection::SM_BUSNAME().asyncCall(msg);
404 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
405 connect(watcher, &QDBusPendingCallWatcher::finished,
406 this, [
this](QDBusPendingCallWatcher* watcher) {
408 QDBusPendingReply<void> reply = *watcher;
409 watcher->deleteLater();
410 if (reply.isError()) {
411 qWarning() <<
"Lock call failed" << reply.error().message();
420 void DBusUnitySessionService::doUnlock()
428 return !d->isSessionActive;
433 Q_EMIT LogoutRequested(
false);
434 Q_EMIT logoutRequested(
false);
439 d->makeLogin1Call(QStringLiteral(
"Reboot"), {
false});
444 Q_EMIT RebootRequested(
false);
445 Q_EMIT rebootRequested(
false);
450 d->makeLogin1Call(QStringLiteral(
"PowerOff"), {
false});
456 d->makeLogin1Call(QStringLiteral(
"Suspend"), {
false});
462 d->makeLogin1Call(QStringLiteral(
"Hibernate"), {
false});
468 d->makeLogin1Call(QStringLiteral(
"HybridSleep"), {
false});
473 Q_EMIT ShutdownRequested(
false);
474 Q_EMIT shutdownRequested(
false);
477 enum class Action : unsigned
486 void performAsyncUnityCall(
const QString &method)
488 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.canonical.Unity"),
489 QStringLiteral(
"/com/canonical/Unity/Session"),
490 QStringLiteral(
"com.canonical.Unity.Session"),
492 QDBusConnection::sessionBus().asyncCall(msg);
496 DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
497 : UnityDBusObject(QStringLiteral(
"/org/gnome/SessionManager"), QStringLiteral(
"org.gnome.SessionManager"))
501 void DBusGnomeSessionManagerWrapper::Logout(quint32 mode)
503 auto call = QStringLiteral(
"RequestLogout");
509 call = QStringLiteral(
"Logout");
511 call = QStringLiteral(
"Logout");
513 performAsyncUnityCall(call);
516 void DBusGnomeSessionManagerWrapper::Reboot()
519 performAsyncUnityCall(QStringLiteral(
"RequestReboot"));
522 void DBusGnomeSessionManagerWrapper::RequestReboot()
525 performAsyncUnityCall(QStringLiteral(
"Reboot"));
528 void DBusGnomeSessionManagerWrapper::RequestShutdown()
531 performAsyncUnityCall(QStringLiteral(
"Shutdown"));
534 void DBusGnomeSessionManagerWrapper::Shutdown()
537 performAsyncUnityCall(QStringLiteral(
"RequestShutdown"));
541 DBusGnomeSessionManagerDialogWrapper::DBusGnomeSessionManagerDialogWrapper()
542 : UnityDBusObject(QStringLiteral(
"/org/gnome/SessionManager/EndSessionDialog"), QStringLiteral(
"com.canonical.Unity"))
546 void DBusGnomeSessionManagerDialogWrapper::Open(
const unsigned type,
const unsigned arg_1,
const unsigned max_wait,
const QList<QDBusObjectPath> &inhibitors)
550 Q_UNUSED(inhibitors);
552 switch (static_cast<Action>(type))
555 performAsyncUnityCall(QStringLiteral(
"RequestLogout"));
559 performAsyncUnityCall(QStringLiteral(
"RequestReboot"));
562 case Action::SHUTDOWN:
563 performAsyncUnityCall(QStringLiteral(
"RequestShutdown"));
572 DBusGnomeScreensaverWrapper::DBusGnomeScreensaverWrapper()
573 : UnityDBusObject(QStringLiteral(
"/org/gnome/ScreenSaver"), QStringLiteral(
"org.gnome.ScreenSaver"))
575 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusGnomeScreensaverWrapper::ActiveChanged);
578 bool DBusGnomeScreensaverWrapper::GetActive()
const 580 return !d->isSessionActive;
583 void DBusGnomeScreensaverWrapper::SetActive(
bool lock)
590 void DBusGnomeScreensaverWrapper::Lock()
592 performAsyncUnityCall(QStringLiteral(
"PromptLock"));
595 quint32 DBusGnomeScreensaverWrapper::GetActiveTime()
const 597 return d->screensaverActiveTime();
600 void DBusGnomeScreensaverWrapper::SimulateUserActivity()
602 d->setIdleHint(
false);
606 DBusScreensaverWrapper::DBusScreensaverWrapper()
607 : UnityDBusObject(QStringLiteral(
"/org/freedesktop/ScreenSaver"), QStringLiteral(
"org.freedesktop.ScreenSaver"))
609 QDBusConnection::sessionBus().registerObject(QStringLiteral(
"/ScreenSaver"),
this, QDBusConnection::ExportScriptableContents);
610 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusScreensaverWrapper::ActiveChanged);
613 bool DBusScreensaverWrapper::GetActive()
const 615 return !d->isSessionActive;
618 bool DBusScreensaverWrapper::SetActive(
bool lock)
627 void DBusScreensaverWrapper::Lock()
629 performAsyncUnityCall(QStringLiteral(
"PromptLock"));
632 quint32 DBusScreensaverWrapper::GetActiveTime()
const 634 return d->screensaverActiveTime();
637 quint32 DBusScreensaverWrapper::GetSessionIdleTime()
const 639 return QDateTime::fromMSecsSinceEpoch(d->idleSinceUSecTimestamp()/1000).secsTo(QDateTime::currentDateTime());
642 void DBusScreensaverWrapper::SimulateUserActivity()
644 d->setIdleHint(
false);
647 #include "dbusunitysessionservice.moc" Q_SCRIPTABLE QString UserName() const
Q_SCRIPTABLE void Reboot()
Q_SCRIPTABLE void RequestLogout()
Q_SCRIPTABLE void RequestReboot()
Q_SCRIPTABLE bool CanSuspend() const
Q_SCRIPTABLE void RequestShutdown()
Q_SCRIPTABLE void HybridSleep()
Q_SCRIPTABLE QString RealName() const
Q_SCRIPTABLE void Hibernate()
Q_SCRIPTABLE bool CanHibernate() const
Q_SCRIPTABLE bool CanLock() const
Q_SCRIPTABLE bool CanShutdown() const
Q_SCRIPTABLE void Shutdown()
Q_SCRIPTABLE void PromptLock()
Q_SCRIPTABLE bool IsLocked() const
Q_SCRIPTABLE void Suspend()
Q_SCRIPTABLE bool CanHybridSleep() const
Q_SCRIPTABLE bool CanReboot() const
Q_SCRIPTABLE void EndSession()
Q_SCRIPTABLE QString HostName() const
Q_SCRIPTABLE void Logout()