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>
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")
41class DBusUnitySessionServicePrivate: public QObject
45 QString logindSessionPath;
46 bool isSessionActive = true;
47 QElapsedTimer screensaverActiveTimer;
48 QDBusUnixFileDescriptor m_systemdInhibitFd;
50 DBusUnitySessionServicePrivate(): QObject() {
57 // get our logind session path
58 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
62 msg << (quint32) getpid();
64 QDBusReply<QDBusObjectPath> reply = QDBusConnection::systemBus().asyncCall(msg);
65 if (reply.isValid()) {
66 logindSessionPath = reply.value().path();
68 // start watching the Active property
69 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, logindSessionPath, "org.freedesktop.DBus.Properties", "PropertiesChanged",
70 this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
72 setupSystemdInhibition();
74 // re-enable the inhibition upon resume from sleep
75 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, "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())
87 // inhibit systemd handling of power/sleep/lid buttons
88 // http://www.freedesktop.org/wiki/Software/systemd/inhibit
90 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, "Inhibit");
91 msg << "handle-power-key:handle-suspend-key:handle-hibernate-key:handle-lid-switch"; // what
92 msg << "Unity"; // who
93 msg << "Unity8 handles power events"; // why
94 msg << "block"; // mode
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 "org.freedesktop.DBus.Properties",
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 "org.freedesktop.DBus.Properties",
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,
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);
217Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
219DBusUnitySessionService::DBusUnitySessionService()
220 : UnityDBusObject("/com/canonical/Unity/Session", "com.canonical.Unity")
222 if (!d->logindSessionPath.isEmpty()) {
223 // connect our Lock() slot to the logind's session Lock() signal
224 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, "Lock", this, SLOT(Lock()));
225 // ... and our Unlocked() signal to the logind's session Unlock() signal
226 // (lightdm handles the unlocking by calling logind's Unlock method which in turn emits this signal we connect to)
227 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, "Unlock", this, SIGNAL(Unlocked()));
229 qWarning() << "Failed to connect to logind's session Lock/Unlock signals";
233void DBusUnitySessionService::Logout()
235 // TODO ask the apps to quit and then emit the signal
236 Q_EMIT LogoutReady();
237 Q_EMIT logoutReady();
240void DBusUnitySessionService::EndSession()
242 const QDBusMessage msg = QDBusMessage::createMethodCall("com.ubuntu.Upstart",
243 "/com/ubuntu/Upstart",
244 "com.ubuntu.Upstart0_6",
246 QDBusConnection::sessionBus().asyncCall(msg);
249bool DBusUnitySessionService::CanHibernate() const
251 return d->checkLogin1Call("CanHibernate");
254bool DBusUnitySessionService::CanSuspend() const
256 return d->checkLogin1Call("CanSuspend");
259bool DBusUnitySessionService::CanHybridSleep() const
261 return d->checkLogin1Call("CanHybridSleep");
264bool DBusUnitySessionService::CanReboot() const
266 return d->checkLogin1Call("CanReboot");
269bool DBusUnitySessionService::CanShutdown() const
271 return d->checkLogin1Call("CanPowerOff");
274bool DBusUnitySessionService::CanLock() const
276 return true; // FIXME
279QString DBusUnitySessionService::UserName() const
281 struct passwd *p = getpwuid(geteuid());
283 return QString::fromUtf8(p->pw_name);
289QString DBusUnitySessionService::RealName() const
291 struct passwd *p = getpwuid(geteuid());
293 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
294 if (!gecos.isEmpty()) {
295 return gecos.split(QLatin1Char(',')).first();
302QString DBusUnitySessionService::HostName() const
305 if (gethostname(hostName, sizeof(hostName)) == -1) {
306 qWarning() << "Could not determine local hostname";
309 hostName[sizeof(hostName) - 1] = '\0';
310 return QString::fromLocal8Bit(hostName);
313void DBusUnitySessionService::PromptLock()
315 Q_EMIT LockRequested();
316 Q_EMIT lockRequested();
319void DBusUnitySessionService::Lock()
321 // lock the session using the org.freedesktop.DisplayManager system DBUS service
322 const QString sessionPath = QString::fromLocal8Bit(qgetenv("XDG_SESSION_PATH"));
323 QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DisplayManager",
325 "org.freedesktop.DisplayManager.Session",
327 QDBusReply<void> reply = QDBusConnection::systemBus().asyncCall(msg);
328 if (!reply.isValid()) {
329 qWarning() << "Lock call failed" << reply.error().message();
331 // emit Locked when the call succeeds
336bool DBusUnitySessionService::IsLocked() const
338 return !d->isSessionActive;
341void DBusUnitySessionService::RequestLogout()
343 Q_EMIT LogoutRequested(false);
344 Q_EMIT logoutRequested(false);
347void DBusUnitySessionService::Reboot()
349 d->makeLogin1Call("Reboot", {false});
352void DBusUnitySessionService::RequestReboot()
354 Q_EMIT RebootRequested(false);
355 Q_EMIT rebootRequested(false);
358void DBusUnitySessionService::Shutdown()
360 d->makeLogin1Call("PowerOff", {false});
363void DBusUnitySessionService::Suspend()
365 d->makeLogin1Call("Suspend", {false});
368void DBusUnitySessionService::Hibernate()
370 d->makeLogin1Call("Hibernate", {false});
373void DBusUnitySessionService::HybridSleep()
375 d->makeLogin1Call("HybridSleep", {false});
378void DBusUnitySessionService::RequestShutdown()
380 Q_EMIT ShutdownRequested(false);
381 Q_EMIT shutdownRequested(false);
384enum class Action : unsigned
393void performAsyncUnityCall(const QString &method)
395 const QDBusMessage msg = QDBusMessage::createMethodCall("com.canonical.Unity",
396 "/com/canonical/Unity/Session",
397 "com.canonical.Unity.Session",
399 QDBusConnection::sessionBus().asyncCall(msg);
403DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
404 : UnityDBusObject("/org/gnome/SessionManager/EndSessionDialog", "com.canonical.Unity")
408void DBusGnomeSessionManagerWrapper::Open(const unsigned type, const unsigned arg_1, const unsigned max_wait, const QList<QDBusObjectPath> &inhibitors)
412 Q_UNUSED(inhibitors);
414 switch (static_cast<Action>(type))
417 performAsyncUnityCall("RequestLogout");
421 performAsyncUnityCall("RequestReboot");
424 case Action::SHUTDOWN:
425 performAsyncUnityCall("RequestShutdown");
434DBusGnomeScreensaverWrapper::DBusGnomeScreensaverWrapper()
435 : UnityDBusObject("/org/gnome/ScreenSaver", "org.gnome.ScreenSaver")
437 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged, this, &DBusGnomeScreensaverWrapper::ActiveChanged);
440bool DBusGnomeScreensaverWrapper::GetActive() const
442 return !d->isSessionActive; // return whether the session is not active
445void DBusGnomeScreensaverWrapper::SetActive(bool lock)
452void DBusGnomeScreensaverWrapper::Lock()
454 performAsyncUnityCall("Lock");
457quint32 DBusGnomeScreensaverWrapper::GetActiveTime() const
459 return d->screensaverActiveTime();
462void DBusGnomeScreensaverWrapper::SimulateUserActivity()
464 d->setIdleHint(false);
468DBusScreensaverWrapper::DBusScreensaverWrapper()
469 : UnityDBusObject("/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver")
471 QDBusConnection::sessionBus().registerObject("/ScreenSaver", this, QDBusConnection::ExportScriptableContents); // compat path, also register here
472 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged, this, &DBusScreensaverWrapper::ActiveChanged);
475bool DBusScreensaverWrapper::GetActive() const
477 return !d->isSessionActive; // return whether the session is not active
480bool DBusScreensaverWrapper::SetActive(bool lock)
489void DBusScreensaverWrapper::Lock()
491 performAsyncUnityCall("Lock");
494quint32 DBusScreensaverWrapper::GetActiveTime() const
496 return d->screensaverActiveTime();
499quint32 DBusScreensaverWrapper::GetSessionIdleTime() const
501 return QDateTime::fromMSecsSinceEpoch(d->idleSinceUSecTimestamp()/1000).secsTo(QDateTime::currentDateTime());
504void DBusScreensaverWrapper::SimulateUserActivity()
506 d->setIdleHint(false);
509#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