on 1b4804e help sign in
unity8/plugins/Unity/Session/dbusunitysessionservice.cpp
473 lines 14 kB history raw
1/*
2 * Copyright (C) 2014, 2015 Canonical, Ltd.
3 *
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.
7 *
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.
12 *
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/>.
15 *
16 * Authors: Lukáš Tinkl <ltinkl@canonical.com>
17 * Christopher Townsend <christopher.townsend@canonical.com>
18 * Ying-Chun Liu (PaulLiu) <paul.liu@canonical.com>
19 */
21// local
22#include "dbusunitysessionservice.h"
24// system
25#include <sys/types.h>
26#include <unistd.h>
27#include <pwd.h>
29// Qt
30#include <QDebug>
31#include <QDBusPendingCall>
32#include <QDBusReply>
33#include <QElapsedTimer>
34#include <QDateTime>
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
46 Q_OBJECT
47public:
48 QString logindSessionPath;
49 bool isSessionActive = true;
50 QElapsedTimer screensaverActiveTimer;
52 DBusUnitySessionServicePrivate(): QObject() {
53 init();
54 checkActive();
55 }
57 void init()
58 {
59 // get our logind session path
60 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
61 LOGIN1_PATH,
62 LOGIN1_IFACE,
63 "GetSessionByPID");
64 msg << (quint32) getpid();
66 QDBusReply<QDBusObjectPath> reply = QDBusConnection::systemBus().asyncCall(msg);
67 if (reply.isValid()) {
68 logindSessionPath = reply.value().path();
69 //qDebug() << "session path" << logindSessionPath;
71 // start watching the Active property
72 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, logindSessionPath, "org.freedesktop.DBus.Properties", "PropertiesChanged",
73 this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
74 } else {
75 qWarning() << "Failed to get logind session path" << reply.error().message();
76 }
77 }
79 bool checkLogin1Call(const QString &method) const
80 {
81 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_IFACE, method);
82 QDBusReply<QString> reply = QDBusConnection::systemBus().asyncCall(msg);
83 return reply.isValid() && (reply == QStringLiteral("yes") || reply == QStringLiteral("challenge"));
84 }
86 void makeLogin1Call(const QString &method, const QVariantList &args)
87 {
88 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
89 LOGIN1_PATH,
90 LOGIN1_IFACE,
91 method);
92 msg.setArguments(args);
93 QDBusConnection::systemBus().asyncCall(msg);
94 }
96 void checkActive()
97 {
98 if (logindSessionPath.isEmpty()) {
99 qWarning() << "Invalid session path";
100 return;
101 }
103 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
104 logindSessionPath,
105 "org.freedesktop.DBus.Properties",
106 "Get");
107 msg << LOGIN1_SESSION_IFACE;
108 msg << ACTIVE_KEY;
110 QDBusReply<QVariant> reply = QDBusConnection::systemBus().asyncCall(msg);
111 if (reply.isValid()) {
112 isSessionActive = reply.value().toBool();
113 qDebug() << "Session" << logindSessionPath << "is active:" << isSessionActive;
114 } else {
115 qWarning() << "Failed to get Active property" << reply.error().message();
116 }
117 }
119 quint32 screensaverActiveTime() const
120 {
121 if (!isSessionActive && screensaverActiveTimer.isValid()) {
122 return screensaverActiveTimer.elapsed() / 1000;
123 }
125 return 0;
126 }
128 quint64 idleSinceUSecTimestamp() const
129 {
130 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
131 logindSessionPath,
132 "org.freedesktop.DBus.Properties",
133 "Get");
134 msg << LOGIN1_SESSION_IFACE;
135 msg << IDLE_SINCE_KEY;
137 QDBusReply<QVariant> reply = QDBusConnection::systemBus().asyncCall(msg);
138 if (reply.isValid()) {
139 return reply.value().value<quint64>();
140 } else {
141 qWarning() << "Failed to get IdleSinceHint property" << reply.error().message();
142 }
144 return 0;
145 }
147 void setIdleHint(bool idle)
148 {
149 QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
150 logindSessionPath,
151 LOGIN1_SESSION_IFACE,
152 "SetIdleHint");
153 msg << idle;
154 QDBusConnection::systemBus().asyncCall(msg);
155 }
157private Q_SLOTS:
158 void onPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps)
159 {
160 Q_UNUSED(iface)
162 if (changedProps.contains(ACTIVE_KEY) || invalidatedProps.contains(ACTIVE_KEY)) {
163 if (changedProps.value(ACTIVE_KEY).isValid()) {
164 isSessionActive = changedProps.value(ACTIVE_KEY).toBool();
165 } else {
166 checkActive();
167 }
169 Q_EMIT screensaverActiveChanged(!isSessionActive);
171 if (isSessionActive) {
172 screensaverActiveTimer.invalidate();
173 setIdleHint(false);
174 } else {
175 screensaverActiveTimer.start();
176 setIdleHint(true);
177 }
178 }
179 }
181Q_SIGNALS:
182 void screensaverActiveChanged(bool active);
183};
185Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
187DBusUnitySessionService::DBusUnitySessionService()
188 : UnityDBusObject("/com/canonical/Unity/Session", "com.canonical.Unity")
190 if (!d->logindSessionPath.isEmpty()) {
191 // connect our Lock() slot to the logind's session Lock() signal
192 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, "Lock", this, SLOT(Lock()));
193 // ... and our Unlocked() signal to the logind's session Unlock() signal
194 // (lightdm handles the unlocking by calling logind's Unlock method which in turn emits this signal we connect to)
195 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, "Unlock", this, SIGNAL(Unlocked()));
196 } else {
197 qWarning() << "Failed to connect to logind's session Lock/Unlock signals";
198 }
201void DBusUnitySessionService::Logout()
203 // TODO ask the apps to quit and then emit the signal
204 Q_EMIT LogoutReady();
207void DBusUnitySessionService::EndSession()
209 const QDBusMessage msg = QDBusMessage::createMethodCall("com.ubuntu.Upstart",
210 "/com/ubuntu/Upstart",
211 "com.ubuntu.Upstart0_6",
212 "EndSession");
213 QDBusConnection::sessionBus().asyncCall(msg);
216bool DBusUnitySessionService::CanHibernate() const
218 return d->checkLogin1Call("CanHibernate");
221bool DBusUnitySessionService::CanSuspend() const
223 return d->checkLogin1Call("CanSuspend");
226bool DBusUnitySessionService::CanHybridSleep() const
228 return d->checkLogin1Call("CanHybridSleep");
231bool DBusUnitySessionService::CanReboot() const
233 return d->checkLogin1Call("CanReboot");
236bool DBusUnitySessionService::CanShutdown() const
238 return d->checkLogin1Call("CanPowerOff");
241bool DBusUnitySessionService::CanLock() const
243 return true; // FIXME
246QString DBusUnitySessionService::UserName() const
248 struct passwd *p = getpwuid(getuid());
249 if (p) {
250 return QString::fromUtf8(p->pw_name);
251 }
253 return QString();
256QString DBusUnitySessionService::RealName() const
258 struct passwd *p = getpwuid(getuid());
259 if (p) {
260 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
261 if (!gecos.isEmpty()) {
262 return gecos.split(QLatin1Char(',')).first();
263 }
264 }
266 return QString();
269QString DBusUnitySessionService::HostName() const
271 char hostName[512];
272 if (gethostname(hostName, sizeof(hostName)) == -1) {
273 qWarning() << "Could not determine local hostname";
274 return QString();
275 }
276 hostName[sizeof(hostName) - 1] = '\0';
277 return QString::fromLocal8Bit(hostName);
280void DBusUnitySessionService::PromptLock()
282 Q_EMIT LockRequested();
285void DBusUnitySessionService::Lock()
287 // lock the session using the org.freedesktop.DisplayManager system DBUS service
288 const QString sessionPath = QString::fromLocal8Bit(qgetenv("XDG_SESSION_PATH"));
289 QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DisplayManager",
290 sessionPath,
291 "org.freedesktop.DisplayManager.Session",
292 "Lock");
293 qDebug() << "Locking session" << msg.path();
294 QDBusReply<void> reply = QDBusConnection::systemBus().asyncCall(msg);
295 if (!reply.isValid()) {
296 qWarning() << "Lock call failed" << reply.error().message();
297 } else {
298 // emit Locked when the call succeeds
299 Q_EMIT Locked();
300 }
303bool DBusUnitySessionService::IsLocked() const
305 return !d->isSessionActive;
308void DBusUnitySessionService::RequestLogout()
310 Q_EMIT LogoutRequested(false);
313void DBusUnitySessionService::Reboot()
315 d->makeLogin1Call("Reboot", {false});
318void DBusUnitySessionService::RequestReboot()
320 Q_EMIT RebootRequested(false);
323void DBusUnitySessionService::Shutdown()
325 d->makeLogin1Call("PowerOff", {false});
328void DBusUnitySessionService::Suspend()
330 d->makeLogin1Call("Suspend", {false});
333void DBusUnitySessionService::Hibernate()
335 d->makeLogin1Call("Hibernate", {false});
338void DBusUnitySessionService::HybridSleep()
340 d->makeLogin1Call("HybridSleep", {false});
343void DBusUnitySessionService::RequestShutdown()
345 Q_EMIT ShutdownRequested(false);
348enum class Action : unsigned
350 LOGOUT = 0,
351 SHUTDOWN,
352 REBOOT,
353 NONE
354};
357void performAsyncUnityCall(const QString &method)
359 const QDBusMessage msg = QDBusMessage::createMethodCall("com.canonical.Unity",
360 "/com/canonical/Unity/Session",
361 "com.canonical.Unity.Session",
362 method);
363 QDBusConnection::sessionBus().asyncCall(msg);
367DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
368 : UnityDBusObject("/org/gnome/SessionManager/EndSessionDialog", "com.canonical.Unity")
372void DBusGnomeSessionManagerWrapper::Open(const unsigned type, const unsigned arg_1, const unsigned max_wait, const QList<QDBusObjectPath> &inhibitors)
374 Q_UNUSED(arg_1);
375 Q_UNUSED(max_wait);
376 Q_UNUSED(inhibitors);
378 switch (static_cast<Action>(type))
379 {
380 case Action::LOGOUT:
381 performAsyncUnityCall("RequestLogout");
382 break;
384 case Action::REBOOT:
385 performAsyncUnityCall("RequestReboot");
386 break;
388 case Action::SHUTDOWN:
389 performAsyncUnityCall("RequestShutdown");
390 break;
392 default:
393 break;
394 }
398DBusGnomeScreensaverWrapper::DBusGnomeScreensaverWrapper()
399 : UnityDBusObject("/org/gnome/ScreenSaver", "org.gnome.ScreenSaver")
401 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged, this, &DBusGnomeScreensaverWrapper::ActiveChanged);
404bool DBusGnomeScreensaverWrapper::GetActive() const
406 return !d->isSessionActive; // return whether the session is not active
409void DBusGnomeScreensaverWrapper::SetActive(bool lock)
411 if (lock) {
412 Lock();
413 }
416void DBusGnomeScreensaverWrapper::Lock()
418 performAsyncUnityCall("Lock");
421quint32 DBusGnomeScreensaverWrapper::GetActiveTime() const
423 return d->screensaverActiveTime();
426void DBusGnomeScreensaverWrapper::SimulateUserActivity()
428 d->setIdleHint(false);
432DBusScreensaverWrapper::DBusScreensaverWrapper()
433 : UnityDBusObject("/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver")
435 QDBusConnection::sessionBus().registerObject("/ScreenSaver", this, QDBusConnection::ExportScriptableContents); // compat path, also register here
436 connect(d, &DBusUnitySessionServicePrivate::screensaverActiveChanged, this, &DBusScreensaverWrapper::ActiveChanged);
439bool DBusScreensaverWrapper::GetActive() const
441 return !d->isSessionActive; // return whether the session is not active
444bool DBusScreensaverWrapper::SetActive(bool lock)
446 if (lock) {
447 Lock();
448 return true;
449 }
450 return false;
453void DBusScreensaverWrapper::Lock()
455 performAsyncUnityCall("Lock");
458quint32 DBusScreensaverWrapper::GetActiveTime() const
460 return d->screensaverActiveTime();
463quint32 DBusScreensaverWrapper::GetSessionIdleTime() const
465 return QDateTime::fromMSecsSinceEpoch(d->idleSinceUSecTimestamp()/1000).secsTo(QDateTime::currentDateTime());
468void DBusScreensaverWrapper::SimulateUserActivity()
470 d->setIdleHint(false);
473#include "dbusunitysessionservice.moc"