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().call(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";
93 msg <<
"Unity8 handles power events";
96 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(msg);
97 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
98 connect(watcher, &QDBusPendingCallWatcher::finished,
99 this, [
this](QDBusPendingCallWatcher* watcher) {
100 QDBusPendingReply<QDBusUnixFileDescriptor> reply = *watcher;
101 watcher->deleteLater();
102 if (reply.isError()) {
103 qWarning() <<
"Failed to inhibit systemd powersave handling" << reply.error().message();
107 m_systemdInhibitFd = reply.value();
111 bool checkLogin1Call(
const QString &method)
const 113 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, method);
114 QDBusReply<QString> reply = QDBusConnection::systemBus().call(msg);
115 return reply.isValid() && (reply == QStringLiteral(
"yes") || reply == QStringLiteral(
"challenge"));
118 void makeLogin1Call(
const QString &method,
const QVariantList &args)
120 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
124 msg.setArguments(args);
125 QDBusConnection::systemBus().asyncCall(msg);
128 void setActive(
bool active)
130 isSessionActive = active;
132 Q_EMIT screensaverActiveChanged(!isSessionActive);
134 if (isSessionActive) {
135 screensaverActiveTimer.invalidate();
138 screensaverActiveTimer.start();
145 if (logindSessionPath.isEmpty()) {
146 qWarning() <<
"Invalid session path";
150 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
152 QStringLiteral(
"org.freedesktop.DBus.Properties"),
153 QStringLiteral(
"Get"));
154 msg << LOGIN1_SESSION_IFACE;
157 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(msg);
158 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
159 connect(watcher, &QDBusPendingCallWatcher::finished,
160 this, [
this](QDBusPendingCallWatcher* watcher) {
162 QDBusPendingReply<QVariant> reply = *watcher;
163 watcher->deleteLater();
164 if (reply.isError()) {
165 qWarning() <<
"Failed to get Active property" << reply.error().message();
169 setActive(reply.value().toBool());
173 quint32 screensaverActiveTime()
const 175 if (!isSessionActive && screensaverActiveTimer.isValid()) {
176 return screensaverActiveTimer.elapsed() / 1000;
182 quint64 idleSinceUSecTimestamp()
const 184 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
186 QStringLiteral(
"org.freedesktop.DBus.Properties"),
187 QStringLiteral(
"Get"));
188 msg << LOGIN1_SESSION_IFACE;
189 msg << IDLE_SINCE_KEY;
191 QDBusReply<QVariant> reply = QDBusConnection::systemBus().call(msg);
192 if (reply.isValid()) {
193 return reply.value().value<quint64>();
195 qWarning() <<
"Failed to get IdleSinceHint property" << reply.error().message();
201 void setIdleHint(
bool idle)
203 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
205 LOGIN1_SESSION_IFACE,
206 QStringLiteral(
"SetIdleHint"));
208 QDBusConnection::systemBus().asyncCall(msg);
212 void onPropertiesChanged(
const QString &iface,
const QVariantMap &changedProps,
const QStringList &invalidatedProps)
216 if (changedProps.contains(ACTIVE_KEY)) {
217 setActive(changedProps.value(ACTIVE_KEY).toBool());
218 }
else if (invalidatedProps.contains(ACTIVE_KEY)) {
223 void onResuming(
bool active)
226 setupSystemdInhibition();
231 void screensaverActiveChanged(
bool active);
234 Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
237 : UnityDBusObject(QStringLiteral("/
com/canonical/Unity/Session"), QStringLiteral("
com.canonical.Unity"))
239 if (!d->logindSessionPath.isEmpty()) {
241 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Lock"),
this, SLOT(Lock()));
244 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral(
"Unlock"),
this, SIGNAL(Unlocked()));
246 qWarning() <<
"Failed to connect to logind's session Lock/Unlock signals";
253 Q_EMIT LogoutReady();
254 Q_EMIT logoutReady();
259 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.ubuntu.Upstart"),
260 QStringLiteral(
"/com/ubuntu/Upstart"),
261 QStringLiteral(
"com.ubuntu.Upstart0_6"),
262 QStringLiteral(
"EndSession"));
263 QDBusConnection::sessionBus().asyncCall(msg);
268 return d->checkLogin1Call(QStringLiteral(
"CanHibernate"));
273 return d->checkLogin1Call(QStringLiteral(
"CanSuspend"));
278 return d->checkLogin1Call(QStringLiteral(
"CanHybridSleep"));
283 return d->checkLogin1Call(QStringLiteral(
"CanReboot"));
288 return d->checkLogin1Call(QStringLiteral(
"CanPowerOff"));
298 struct passwd *p = getpwuid(geteuid());
300 return QString::fromUtf8(p->pw_name);
308 struct passwd *p = getpwuid(geteuid());
310 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
311 if (!gecos.isEmpty()) {
312 const QStringList splitGecos = gecos.split(QLatin1Char(
','));
313 return splitGecos.first();
323 if (gethostname(hostName,
sizeof(hostName)) == -1) {
324 qWarning() <<
"Could not determine local hostname";
327 hostName[
sizeof(hostName) - 1] =
'\0';
328 return QString::fromLocal8Bit(hostName);
333 Q_EMIT LockRequested();
334 Q_EMIT lockRequested();
343 const QString sessionPath = QString::fromLocal8Bit(qgetenv(
"XDG_SESSION_PATH"));
344 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"org.freedesktop.DisplayManager"),
346 QStringLiteral(
"org.freedesktop.DisplayManager.Session"),
347 QStringLiteral(
"Lock"));
349 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(msg);
350 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pendingCall,
this);
351 connect(watcher, &QDBusPendingCallWatcher::finished,
352 this, [
this](QDBusPendingCallWatcher* watcher) {
354 QDBusPendingReply<void> reply = *watcher;
355 watcher->deleteLater();
356 if (reply.isError()) {
357 qWarning() <<
"Lock call failed" << reply.error().message();
368 return !d->isSessionActive;
373 Q_EMIT LogoutRequested(
false);
374 Q_EMIT logoutRequested(
false);
379 d->makeLogin1Call(QStringLiteral(
"Reboot"), {
false});
384 Q_EMIT RebootRequested(
false);
385 Q_EMIT rebootRequested(
false);
390 d->makeLogin1Call(QStringLiteral(
"PowerOff"), {
false});
395 d->makeLogin1Call(QStringLiteral(
"Suspend"), {
false});
400 d->makeLogin1Call(QStringLiteral(
"Hibernate"), {
false});
405 d->makeLogin1Call(QStringLiteral(
"HybridSleep"), {
false});
410 Q_EMIT ShutdownRequested(
false);
411 Q_EMIT shutdownRequested(
false);
414 enum class Action : unsigned
423 void performAsyncUnityCall(
const QString &method)
425 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(
"com.canonical.Unity"),
426 QStringLiteral(
"/com/canonical/Unity/Session"),
427 QStringLiteral(
"com.canonical.Unity.Session"),
429 QDBusConnection::sessionBus().asyncCall(msg);
433 DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
434 : UnityDBusObject(QStringLiteral(
"/org/gnome/SessionManager/EndSessionDialog"), QStringLiteral(
"com.canonical.Unity"))
438 void DBusGnomeSessionManagerWrapper::Open(
const unsigned type,
const unsigned arg_1,
const unsigned max_wait,
const QList<QDBusObjectPath> &inhibitors)
442 Q_UNUSED(inhibitors);
444 switch (static_cast<Action>(type))
447 performAsyncUnityCall(QStringLiteral(
"RequestLogout"));
451 performAsyncUnityCall(QStringLiteral(
"RequestReboot"));
454 case Action::SHUTDOWN:
455 performAsyncUnityCall(QStringLiteral(
"RequestShutdown"));
464 DBusGnomeScreensaverWrapper::DBusGnomeScreensaverWrapper()
465 : UnityDBusObject(QStringLiteral(
"/org/gnome/ScreenSaver"), QStringLiteral(
"org.gnome.ScreenSaver"))
467 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusGnomeScreensaverWrapper::ActiveChanged);
470 bool DBusGnomeScreensaverWrapper::GetActive()
const 472 return !d->isSessionActive;
475 void DBusGnomeScreensaverWrapper::SetActive(
bool lock)
482 void DBusGnomeScreensaverWrapper::Lock()
484 performAsyncUnityCall(QStringLiteral(
"Lock"));
487 quint32 DBusGnomeScreensaverWrapper::GetActiveTime()
const 489 return d->screensaverActiveTime();
492 void DBusGnomeScreensaverWrapper::SimulateUserActivity()
494 d->setIdleHint(
false);
498 DBusScreensaverWrapper::DBusScreensaverWrapper()
499 : UnityDBusObject(QStringLiteral(
"/org/freedesktop/ScreenSaver"), QStringLiteral(
"org.freedesktop.ScreenSaver"))
501 QDBusConnection::sessionBus().registerObject(QStringLiteral(
"/ScreenSaver"),
this, QDBusConnection::ExportScriptableContents);
502 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged,
this, &DBusScreensaverWrapper::ActiveChanged);
505 bool DBusScreensaverWrapper::GetActive()
const 507 return !d->isSessionActive;
510 bool DBusScreensaverWrapper::SetActive(
bool lock)
519 void DBusScreensaverWrapper::Lock()
521 performAsyncUnityCall(QStringLiteral(
"Lock"));
524 quint32 DBusScreensaverWrapper::GetActiveTime()
const 526 return d->screensaverActiveTime();
529 quint32 DBusScreensaverWrapper::GetSessionIdleTime()
const 531 return QDateTime::fromMSecsSinceEpoch(d->idleSinceUSecTimestamp()/1000).secsTo(QDateTime::currentDateTime());
534 void DBusScreensaverWrapper::SimulateUserActivity()
536 d->setIdleHint(
false);
539 #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()