2 * Copyright (C) 2014, 2015 Canonical, Ltd.
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18#include "dbusunitysessionservice.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")
44class DBusUnitySessionServicePrivate: public QObject
48 QString logindSessionPath;
49 bool isSessionActive = true;
50 QElapsedTimer screensaverActiveTimer;
51 QDBusUnixFileDescriptor m_systemdInhibitFd;
53 DBusUnitySessionServicePrivate(): QObject() {
60 // get our logind session path
61 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
64 QStringLiteral("GetSessionByPID"));
65 msg << (quint32) getpid();
67 QDBusReply<QDBusObjectPath> reply = QDBusConnection::systemBus().call(msg);
68 if (reply.isValid()) {
69 logindSessionPath = reply.value().path();
71 // start watching the Active property
72 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, logindSessionPath, QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"),
73 this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
75 setupSystemdInhibition();
77 // re-enable the inhibition upon resume from sleep
78 QDBusConnection::systemBus().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())
90 // inhibit systemd handling of power/sleep/hibernate buttons
91 // http://www.freedesktop.org/wiki/Software/systemd/inhibit
93 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, QStringLiteral("Inhibit"));
94 msg << "handle-power-key:handle-suspend-key:handle-hibernate-key"; // what
95 msg << "Unity"; // who
96 msg << "Unity8 handles power events"; // why
97 msg << "block"; // mode
99 QDBusPendingCall pendingCall = QDBusConnection::systemBus().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::systemBus().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::systemBus().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::systemBus().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::systemBus().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::systemBus().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();
234 void screensaverActiveChanged(bool active);
237Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
239DBusUnitySessionService::DBusUnitySessionService()
240 : UnityDBusObject(QStringLiteral("/com/canonical/Unity/Session"), QStringLiteral("com.canonical.Unity"))
242 if (!d->logindSessionPath.isEmpty()) {
243 // connect our Lock() slot to the logind's session Lock() signal
244 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Lock"), this, SLOT(Lock()));
245 // ... and our Unlocked() signal to the logind's session Unlock() signal
246 // (lightdm handles the unlocking by calling logind's Unlock method which in turn emits this signal we connect to)
247 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Unlock"), this, SIGNAL(Unlocked()));
249 qWarning() << "Failed to connect to logind's session Lock/Unlock signals";
253void DBusUnitySessionService::Logout()
255 // TODO ask the apps to quit and then emit the signal
256 Q_EMIT LogoutReady();
257 Q_EMIT logoutReady();
260void DBusUnitySessionService::EndSession()
262 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("com.ubuntu.Upstart"),
263 QStringLiteral("/com/ubuntu/Upstart"),
264 QStringLiteral("com.ubuntu.Upstart0_6"),
265 QStringLiteral("EndSession"));
266 QDBusConnection::sessionBus().asyncCall(msg);
269bool DBusUnitySessionService::CanHibernate() const
271 return d->checkLogin1Call(QStringLiteral("CanHibernate"));
274bool DBusUnitySessionService::CanSuspend() const
276 return d->checkLogin1Call(QStringLiteral("CanSuspend"));
279bool DBusUnitySessionService::CanHybridSleep() const
281 return d->checkLogin1Call(QStringLiteral("CanHybridSleep"));
284bool DBusUnitySessionService::CanReboot() const
286 return d->checkLogin1Call(QStringLiteral("CanReboot"));
289bool DBusUnitySessionService::CanShutdown() const
291 return d->checkLogin1Call(QStringLiteral("CanPowerOff"));
294bool DBusUnitySessionService::CanLock() const
296 return true; // FIXME
299QString DBusUnitySessionService::UserName() const
301 return QString::fromUtf8(g_get_user_name());
304QString DBusUnitySessionService::RealName() const
306 struct passwd *p = getpwuid(geteuid());
308 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
309 if (!gecos.isEmpty()) {
310 const QStringList splitGecos = gecos.split(QLatin1Char(','));
311 return splitGecos.first();
318QString DBusUnitySessionService::HostName() const
321 if (gethostname(hostName, sizeof(hostName)) == -1) {
322 qWarning() << "Could not determine local hostname";
325 hostName[sizeof(hostName) - 1] = '\0';
326 return QString::fromLocal8Bit(hostName);
329void DBusUnitySessionService::PromptLock()
331 Q_EMIT LockRequested();
332 Q_EMIT lockRequested();
335void DBusUnitySessionService::Lock()
337 // signal u8 to show the lockscreen/greeter
340 // lock the session using the org.freedesktop.DisplayManager system DBUS service
341 const QString sessionPath = QString::fromLocal8Bit(qgetenv("XDG_SESSION_PATH"));
342 QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DisplayManager"),
344 QStringLiteral("org.freedesktop.DisplayManager.Session"),
345 QStringLiteral("Lock"));
347 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(msg);
348 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this);
349 connect(watcher, &QDBusPendingCallWatcher::finished,
350 this, [this](QDBusPendingCallWatcher* watcher) {
352 QDBusPendingReply<void> reply = *watcher;
353 watcher->deleteLater();
354 if (reply.isError()) {
355 qWarning() << "Lock call failed" << reply.error().message();
359 // emit Locked when the call succeeds
364bool DBusUnitySessionService::IsLocked() const
366 return !d->isSessionActive;
369void DBusUnitySessionService::RequestLogout()
371 Q_EMIT LogoutRequested(false);
372 Q_EMIT logoutRequested(false);
375void DBusUnitySessionService::Reboot()
377 d->makeLogin1Call(QStringLiteral("Reboot"), {false});
380void DBusUnitySessionService::RequestReboot()
382 Q_EMIT RebootRequested(false);
383 Q_EMIT rebootRequested(false);
386void DBusUnitySessionService::Shutdown()
388 d->makeLogin1Call(QStringLiteral("PowerOff"), {false});
391void DBusUnitySessionService::Suspend()
393 d->makeLogin1Call(QStringLiteral("Suspend"), {false});
396void DBusUnitySessionService::Hibernate()
398 d->makeLogin1Call(QStringLiteral("Hibernate"), {false});
401void DBusUnitySessionService::HybridSleep()
403 d->makeLogin1Call(QStringLiteral("HybridSleep"), {false});
406void DBusUnitySessionService::RequestShutdown()
408 Q_EMIT ShutdownRequested(false);
409 Q_EMIT shutdownRequested(false);
412enum class Action : unsigned
421void performAsyncUnityCall(const QString &method)
423 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("com.canonical.Unity"),
424 QStringLiteral("/com/canonical/Unity/Session"),
425 QStringLiteral("com.canonical.Unity.Session"),
427 QDBusConnection::sessionBus().asyncCall(msg);
431DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
432 : UnityDBusObject(QStringLiteral("/org/gnome/SessionManager/EndSessionDialog"), QStringLiteral("com.canonical.Unity"))
436void DBusGnomeSessionManagerWrapper::Open(const unsigned type, const unsigned arg_1, const unsigned max_wait, const QList<QDBusObjectPath> &inhibitors)
440 Q_UNUSED(inhibitors);
442 switch (static_cast<Action>(type))
445 performAsyncUnityCall(QStringLiteral("RequestLogout"));
449 performAsyncUnityCall(QStringLiteral("RequestReboot"));
452 case Action::SHUTDOWN:
453 performAsyncUnityCall(QStringLiteral("RequestShutdown"));
462DBusGnomeScreensaverWrapper::DBusGnomeScreensaverWrapper()
463 : UnityDBusObject(QStringLiteral("/org/gnome/ScreenSaver"), QStringLiteral("org.gnome.ScreenSaver"))
465 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged, this, &DBusGnomeScreensaverWrapper::ActiveChanged);
468bool DBusGnomeScreensaverWrapper::GetActive() const
470 return !d->isSessionActive; // return whether the session is not active
473void DBusGnomeScreensaverWrapper::SetActive(bool lock)
480void DBusGnomeScreensaverWrapper::Lock()
482 performAsyncUnityCall(QStringLiteral("Lock"));
485quint32 DBusGnomeScreensaverWrapper::GetActiveTime() const
487 return d->screensaverActiveTime();
490void DBusGnomeScreensaverWrapper::SimulateUserActivity()
492 d->setIdleHint(false);
496DBusScreensaverWrapper::DBusScreensaverWrapper()
497 : UnityDBusObject(QStringLiteral("/org/freedesktop/ScreenSaver"), QStringLiteral("org.freedesktop.ScreenSaver"))
499 QDBusConnection::sessionBus().registerObject(QStringLiteral("/ScreenSaver"), this, QDBusConnection::ExportScriptableContents); // compat path, also register here
500 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged, this, &DBusScreensaverWrapper::ActiveChanged);
503bool DBusScreensaverWrapper::GetActive() const
505 return !d->isSessionActive; // return whether the session is not active
508bool DBusScreensaverWrapper::SetActive(bool lock)
517void DBusScreensaverWrapper::Lock()
519 performAsyncUnityCall(QStringLiteral("Lock"));
522quint32 DBusScreensaverWrapper::GetActiveTime() const
524 return d->screensaverActiveTime();
527quint32 DBusScreensaverWrapper::GetSessionIdleTime() const
529 return QDateTime::fromMSecsSinceEpoch(d->idleSinceUSecTimestamp()/1000).secsTo(QDateTime::currentDateTime());
532void DBusScreensaverWrapper::SimulateUserActivity()
534 d->setIdleHint(false);
537#include "dbusunitysessionservice.moc"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list