Merge lp:~lukas-kde/unity8/screenInhibitions into lp:unity8

Proposed by Lukáš Tinkl
Status: Work in progress
Proposed branch: lp:~lukas-kde/unity8/screenInhibitions
Merge into: lp:unity8
Diff against target: 722 lines (+323/-64)
10 files modified
plugins/Unity/Session/CMakeLists.txt (+2/-0)
plugins/Unity/Session/dbusunitysessionservice.cpp (+237/-28)
plugins/Unity/Session/dbusunitysessionservice.h (+37/-2)
qml/Components/Dialogs.qml (+3/-3)
qml/Shell.qml (+1/-19)
qml/Stage/Stage.qml (+39/-4)
src/libunity8-private/unitydbusobject.cpp (+1/-6)
src/libunity8-private/unitydbusobject.h (+0/-1)
tests/plugins/Unity/Session/CMakeLists.txt (+2/-0)
tests/plugins/Unity/Session/LogindServer.h (+1/-1)
To merge this branch: bzr merge lp:~lukas-kde/unity8/screenInhibitions
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
Michael Zanetti Pending
Review via email: mp+309796@code.launchpad.net

This proposal supersedes a proposal from 2016-10-14.

Commit message

Implement the FDO Inhibit DBUS API

Description of the change

This implements the de-facto freedesktop.org inhibit standard, as described in https://people.freedesktop.org/~hadess/idle-inhibition-spec/re01.html. This standard is implemented by KDE, Gnome and most recently also Unity 7. Apps like Chrome or VLC can then use the DBUS published Inhibit/UnInhibit methods to ask the shell to suspend the screen blanking mechanism.

For the actual screenlock/saver keyboard shortcuts and dialogs, do not overpass the backend.

Simplify the *name* methods, add some missing documentation.

Checklist:

* Are there any related MPs required for this MP to build/function as expected? Please list.

No

* Did you perform an exploratory manual test run of your code change and any related functionality?

Yes

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?

N/A

* If you changed the UI, has there been a design review?

N/A (no GUI change)

To post a comment you must log in.
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

In general it works, even from Firefox in libertine when watching a youtube video. However, if you close firefox while it's playing a video, it won't dispatch the Uninhibit call and the screen stays lit...

review: Needs Fixing
Revision history for this message
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal

> In general it works, even from Firefox in libertine when watching a youtube video. However, if you close firefox while it's playing a video, it won't dispatch the Uninhibit call and the screen stays lit...

Oh yeah we totally need to track the requests and pop the ones where
requesters are gone.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2662
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2361/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3114
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1758
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1758
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=qmluitests.sh/1758
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3142
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2998/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2998
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2998/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2361/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

looks better in handling bad/crashing/disappearing apps, but as agreed on in chat, let's also add the monitoring for focused/visible in this branch directly. Putting back to WIP.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2664
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2367/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3120
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1764
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1764
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=qmluitests.sh/1764
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3148
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3004/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/3004
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/3004/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2367/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
2683. By Lukáš Tinkl

use ual instead of qtmir::AppMan for the whitelisting of PIDs

Revision history for this message
Gerry Boland (gerboland) wrote :

If you need an api in AppMan to wrap UAL's hasPid(), I'm happy to add it to qtmir. I just don't want to expose a list of PIDs for shell use.

2684. By Lukáš Tinkl

merge trunk

2685. By Lukáš Tinkl

merge trunk

2686. By Lukáš Tinkl

merge trunk

Unmerged revisions

2686. By Lukáš Tinkl

merge trunk

2685. By Lukáš Tinkl

merge trunk

2684. By Lukáš Tinkl

merge trunk

2683. By Lukáš Tinkl

use ual instead of qtmir::AppMan for the whitelisting of PIDs

2682. By Lukáš Tinkl

implement pidsForApplicationid()

2681. By Lukáš Tinkl

merge trunk

2680. By Lukáš Tinkl

fix PID type, get rid of Upstart

2679. By Lukáš Tinkl

don't take minimized delegates into account for the whitelist

2678. By Lukáš Tinkl

fix the whitelist checking

PID is different for DBUS and container apps :/

2677. By Lukáš Tinkl

fix the pid prop properly

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Unity/Session/CMakeLists.txt'
2--- plugins/Unity/Session/CMakeLists.txt 2016-06-21 14:23:49 +0000
3+++ plugins/Unity/Session/CMakeLists.txt 2016-11-22 09:36:12 +0000
4@@ -3,6 +3,7 @@
5 ${CMAKE_CURRENT_BINARY_DIR}
6 ${GIO_INCLUDE_DIRS}
7 ${GLIB_INCLUDE_DIRS}
8+ ${UAL_INCLUDE_DIRS}
9 ${libunity8-private_SOURCE_DIR}
10 )
11
12@@ -23,6 +24,7 @@
13 unity8-private
14 ${GIO_LDFLAGS}
15 ${GLIB_LIBRARIES}
16+ ${UAL_LIBRARIES}
17 )
18
19 # export the qmldir and qmltypes files
20
21=== modified file 'plugins/Unity/Session/dbusunitysessionservice.cpp'
22--- plugins/Unity/Session/dbusunitysessionservice.cpp 2016-06-22 13:38:16 +0000
23+++ plugins/Unity/Session/dbusunitysessionservice.cpp 2016-11-22 09:36:12 +0000
24@@ -1,5 +1,5 @@
25 /*
26- * Copyright (C) 2014, 2015 Canonical, Ltd.
27+ * Copyright (C) 2014-2016 Canonical, Ltd.
28 *
29 * This program is free software: you can redistribute it and/or modify it under
30 * the terms of the GNU Lesser General Public License version 3, as published by
31@@ -21,6 +21,7 @@
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <pwd.h>
35+#include <algorithm>
36
37 // Qt
38 #include <QDebug>
39@@ -29,6 +30,14 @@
40 #include <QElapsedTimer>
41 #include <QDateTime>
42 #include <QDBusUnixFileDescriptor>
43+#include <QDBusServiceWatcher>
44+#include <QDBusConnectionInterface>
45+#include <QPointer>
46+
47+// ual
48+#include <ubuntu-app-launch/appid.h>
49+#include <ubuntu-app-launch/application.h>
50+#include <ubuntu-app-launch/registry.h>
51
52 // Glib
53 #include <glib.h>
54@@ -41,16 +50,39 @@
55 #define ACTIVE_KEY QStringLiteral("Active")
56 #define IDLE_SINCE_KEY QStringLiteral("IdleSinceHint")
57
58+#define UNITY_SCREEN_SERVICE QStringLiteral("com.canonical.Unity.Screen")
59+#define UNITY_SCREEN_PATH QStringLiteral("/com/canonical/Unity/Screen")
60+#define UNITY_SCREEN_IFACE QStringLiteral("com.canonical.Unity.Screen")
61+
62+namespace ual = ubuntu::app_launch;
63+
64+struct InhibitionInfo {
65+ int cookie{0};
66+ QString dbusAppName;
67+ QString dbusReason;
68+ QString dbusService;
69+ pid_t pid{0};
70+};
71+
72 class DBusUnitySessionServicePrivate: public QObject
73 {
74 Q_OBJECT
75 public:
76 QString logindSessionPath;
77- bool isSessionActive = true;
78+ bool isSessionActive{true};
79 QElapsedTimer screensaverActiveTimer;
80 QDBusUnixFileDescriptor m_systemdInhibitFd;
81
82- DBusUnitySessionServicePrivate(): QObject() {
83+ // inhibit stuff
84+ QPointer<QDBusServiceWatcher> busWatcher;
85+ std::list<InhibitionInfo> inhibitions;
86+ QStringList screenInhibitionsWhitelist; // list of appIds
87+ std::shared_ptr<ual::Registry> m_ualRegistry{std::make_shared<ual::Registry>()};
88+
89+ DBusUnitySessionServicePrivate():
90+ QObject()
91+ , busWatcher(new QDBusServiceWatcher(this))
92+ {
93 init();
94 checkActive();
95 }
96@@ -80,6 +112,11 @@
97 } else {
98 qWarning() << "Failed to get logind session path" << reply.error().message();
99 }
100+
101+ // watch services
102+ busWatcher->setConnection(QDBusConnection::sessionBus());
103+ busWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
104+ connect(busWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &DBusUnitySessionServicePrivate::onServiceUnregistered);
105 }
106
107 void setupSystemdInhibition()
108@@ -128,6 +165,7 @@
109 QDBusConnection::SM_BUSNAME().asyncCall(msg);
110 }
111
112+ // set the session as active or inactive
113 void setActive(bool active)
114 {
115 isSessionActive = active;
116@@ -211,6 +249,139 @@
117 QDBusConnection::SM_BUSNAME().asyncCall(msg);
118 }
119
120+ /**
121+ * Register inhibition, enable it if on whitelist
122+ *
123+ * @return the inhibition cookie, or 0 if the call didn't succeed
124+ */
125+ int addInhibition(const QString &service, int pid, const QString &appName, const QString &reason)
126+ {
127+ InhibitionInfo inh;
128+ inh.dbusAppName = appName;
129+ inh.dbusReason = reason;
130+ inh.dbusService = service;
131+ inh.pid = static_cast<pid_t>(pid);
132+
133+ int cookie = 0;
134+
135+ if (whiteListCheck(pid)) {
136+ cookie = addInhibitionHelper();
137+ if (cookie > 0) {
138+ inh.cookie = cookie;
139+ }
140+ } else
141+ qDebug() << "!!! Whitelist doesn't contain pid:" << pid << screenInhibitionsWhitelist;
142+
143+ if (!busWatcher.isNull() && !service.isEmpty() && !busWatcher->watchedServices().contains(service)) {
144+ qDebug() << "!!! Started watching service:" << service;
145+ busWatcher->addWatchedService(service);
146+ }
147+
148+ qDebug() << "!!! addInhibition, cookie:" << cookie;
149+
150+ inhibitions.push_back(inh);
151+ return cookie;
152+ }
153+
154+ /**
155+ * Ask repowerd to keep the display on (enable the inhibition), start watching the service
156+ * @return cookie, 0 in failure
157+ */
158+ int addInhibitionHelper()
159+ {
160+ QDBusMessage msg = QDBusMessage::createMethodCall(UNITY_SCREEN_SERVICE, UNITY_SCREEN_PATH, UNITY_SCREEN_IFACE, QStringLiteral("keepDisplayOn"));
161+ QDBusReply<int> cookie = QDBusConnection::SM_BUSNAME().call(msg);
162+ if (cookie.isValid()) {
163+ return cookie;
164+ } else {
165+ qWarning() << "Failed to inhibit screen blanking" << cookie.error().message();
166+ }
167+
168+ return 0;
169+ }
170+
171+ /**
172+ * Release the repowerd screen inhibition based on @p cookie
173+ */
174+ void removeInhibition(int cookie)
175+ {
176+ qDebug() << "!!! removeInhibition, cookie:" << cookie;
177+ QDBusMessage msg = QDBusMessage::createMethodCall(UNITY_SCREEN_SERVICE, UNITY_SCREEN_PATH, UNITY_SCREEN_IFACE, QStringLiteral("removeDisplayOnRequest"));
178+ msg << cookie;
179+ QDBusReply<void> reply = QDBusConnection::SM_BUSNAME().call(msg);
180+ if (!reply.isValid()) {
181+ qWarning() << "Failed to release screen blanking inhibition" << reply.error().message();
182+ }
183+ }
184+
185+ /**
186+ * Drop the inhibition from the list with the matching @p cookie, cleaning up the bus watcher as well if needed
187+ */
188+ void removeInhibitionHelper(int cookie)
189+ {
190+ qDebug() << "!!! removeInhibitionHelper, cookie:" << cookie;
191+ // drop the inhibition from the list with the matching cookie
192+ QString service;
193+ inhibitions.remove_if([&service, cookie](const InhibitionInfo & inh) {service = inh.dbusService; return inh.cookie == cookie;});
194+
195+ qDebug() << "!!! Removed inhibition for service?:" << service;
196+
197+ if (!busWatcher.isNull() && std::none_of(inhibitions.cbegin(), inhibitions.cend(),
198+ [service](const InhibitionInfo & inh){return inh.dbusService == service;})) {
199+ // no cookies from service left
200+ qDebug() << "!!! Stopped watching service:" << service;
201+ busWatcher->removeWatchedService(service);
202+ }
203+ }
204+
205+ /**
206+ * Enable/disable inhibitions dynamically as the whitelist changes
207+ */
208+ void updateInhibitions()
209+ {
210+ qDebug() << "!!! Update inhibitions, empty?" << inhibitions.empty();
211+ if (inhibitions.empty()) // no inhibitions set up, bail out
212+ return;
213+
214+ qDebug() << "!!! Update inhibitions, whitelist of PIDs:" << screenInhibitionsWhitelist;
215+
216+ for (InhibitionInfo inh: inhibitions) {
217+ if (!whiteListCheck(inh.pid)) { // not on whitelist anymore, disable temporarily
218+ qDebug() << "!!! Disabling inhibition, not on whitelist:" << inh.dbusService;
219+ removeInhibition(inh.cookie);
220+ inh.cookie = 0; // reset the cookie
221+ } else if (whiteListCheck(inh.pid) && inh.cookie == 0) { // on whitelist but not enabled
222+ qDebug() << "!!! Enabling inhibition, on whitelist but not enabled:" << inh.dbusService;
223+ inh.cookie = addInhibitionHelper();
224+ }
225+ }
226+ }
227+
228+ bool whiteListCheck(pid_t pid) const {
229+ Q_FOREACH(const QString &appId, screenInhibitionsWhitelist) {
230+ ual::AppID ualAppId = ual::AppID::find(m_ualRegistry, appId.toStdString());
231+ if (ualAppId.empty()) {
232+ continue;
233+ }
234+
235+ std::shared_ptr<ual::Application> ualApp;
236+ try {
237+ ualApp = ual::Application::create(ualAppId, m_ualRegistry);
238+ }
239+ catch (std::runtime_error &e) {
240+ qWarning() << "Couldn't find UAL application object for" << appId << "-" << e.what();
241+ continue;
242+ }
243+ if (ualApp) {
244+ if (std::any_of(ualApp->instances().cbegin(), ualApp->instances().cend(),
245+ [pid](const std::shared_ptr<ual::Application::Instance> &inst){ return inst && inst->hasPid(pid); })) {
246+ return true;
247+ }
248+ }
249+ }
250+ return false;
251+ }
252+
253 private Q_SLOTS:
254 void onPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps)
255 {
256@@ -232,6 +403,19 @@
257 }
258 }
259
260+ void onServiceUnregistered(const QString &service)
261+ {
262+ // cleanup inhibitions
263+ qDebug() << "!!! Cleanup inhibitions";
264+ Q_FOREACH(InhibitionInfo inh, inhibitions) {
265+ if (inh.dbusService == service) {
266+ qDebug() << "!!! Cleaning up cookie" << inh.cookie << ", after service:" << inh.dbusService;
267+ removeInhibition(inh.cookie);
268+ removeInhibitionHelper(inh.cookie);
269+ }
270+ }
271+ }
272+
273 Q_SIGNALS:
274 void screensaverActiveChanged(bool active);
275 void prepareForSleep();
276@@ -245,7 +429,7 @@
277 if (!d->logindSessionPath.isEmpty()) {
278 // connect our PromptLock() slot to the logind's session Lock() signal
279 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Lock"), this, SLOT(PromptLock()));
280- // ... and our Unlocked() signal to the logind's session Unlock() signal
281+ // ... and our doUnlock() slot to the logind's session Unlock() signal
282 // (lightdm handles the unlocking by calling logind's Unlock method which in turn emits this signal we connect to)
283 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Unlock"), this, SLOT(doUnlock()));
284 connect(d, &DBusUnitySessionServicePrivate::prepareForSleep, this, &DBusUnitySessionService::PromptLock);
285@@ -254,6 +438,22 @@
286 }
287 }
288
289+QStringList DBusUnitySessionService::screenInhibitionsWhitelist() const
290+{
291+ return d->screenInhibitionsWhitelist;
292+}
293+
294+void DBusUnitySessionService::setScreenInhibitionsWhitelist(const QStringList &screenInhibitionsWhitelist)
295+{
296+ qDebug() << "!!! Update whitelist, new one:" << screenInhibitionsWhitelist << ", old one:" << d->screenInhibitionsWhitelist;
297+ if (std::is_permutation(screenInhibitionsWhitelist.begin(), screenInhibitionsWhitelist.end(), d->screenInhibitionsWhitelist.begin()))
298+ return;
299+
300+ d->screenInhibitionsWhitelist = screenInhibitionsWhitelist;
301+ Q_EMIT screenInhibitionsWhitelistChanged();
302+ d->updateInhibitions();
303+}
304+
305 void DBusUnitySessionService::Logout()
306 {
307 // TODO ask the apps to quit and then emit the signal
308@@ -263,11 +463,11 @@
309
310 void DBusUnitySessionService::EndSession()
311 {
312- const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("com.ubuntu.Upstart"),
313- QStringLiteral("/com/ubuntu/Upstart"),
314- QStringLiteral("com.ubuntu.Upstart0_6"),
315- QStringLiteral("EndSession"));
316- QDBusConnection::sessionBus().asyncCall(msg);
317+ const QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
318+ d->logindSessionPath,
319+ LOGIN1_SESSION_IFACE,
320+ QStringLiteral("Terminate"));
321+ QDBusConnection::SM_BUSNAME().asyncCall(msg);
322 }
323
324 bool DBusUnitySessionService::CanHibernate() const
325@@ -307,27 +507,12 @@
326
327 QString DBusUnitySessionService::RealName() const
328 {
329- struct passwd *p = getpwuid(geteuid());
330- if (p) {
331- const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
332- if (!gecos.isEmpty()) {
333- const QStringList splitGecos = gecos.split(QLatin1Char(','));
334- return splitGecos.first();
335- }
336- }
337-
338- return QString();
339+ return QString::fromUtf8(g_get_real_name());
340 }
341
342 QString DBusUnitySessionService::HostName() const
343 {
344- char hostName[512];
345- if (gethostname(hostName, sizeof(hostName)) == -1) {
346- qWarning() << "Could not determine local hostname";
347- return QString();
348- }
349- hostName[sizeof(hostName) - 1] = '\0';
350- return QString::fromLocal8Bit(hostName);
351+ return QString::fromUtf8(g_get_host_name());
352 }
353
354 void DBusUnitySessionService::PromptLock()
355@@ -337,6 +522,7 @@
356 // user session.
357 Q_EMIT LockRequested();
358 Q_EMIT lockRequested();
359+ d->setActive(false);
360 }
361
362 void DBusUnitySessionService::Lock()
363@@ -395,6 +581,7 @@
364 {
365 Q_EMIT Unlocked();
366 Q_EMIT unlocked();
367+ d->setActive(true);
368 }
369
370 bool DBusUnitySessionService::IsLocked() const
371@@ -528,7 +715,7 @@
372
373 void DBusGnomeScreensaverWrapper::SimulateUserActivity()
374 {
375- d->setIdleHint(false);
376+ d->setActive(true);
377 }
378
379
380@@ -570,7 +757,29 @@
381
382 void DBusScreensaverWrapper::SimulateUserActivity()
383 {
384- d->setIdleHint(false);
385+ d->setActive(true);
386+}
387+
388+uint DBusScreensaverWrapper::Inhibit(const QString &appName, const QString &reason)
389+{
390+ QString service;
391+ int pid = 0;
392+ if (calledFromDBus()) {
393+ service = message().service();
394+ pid = connection().interface()->servicePid(service);
395+ }
396+ qDebug() << "!!! INHIBIT (appName, reason, dbusService, pid)" << appName << reason << service << pid;
397+ uint cookie = static_cast<uint>(d->addInhibition(service, pid, appName, reason));
398+ d->checkActive();
399+ return cookie;
400+}
401+
402+void DBusScreensaverWrapper::UnInhibit(uint cookie)
403+{
404+ qDebug() << "!!! UNINHIBIT (cookie)" << cookie;
405+ d->removeInhibition(cookie);
406+ d->removeInhibitionHelper(cookie);
407+ d->checkActive();
408 }
409
410 #include "dbusunitysessionservice.moc"
411
412=== modified file 'plugins/Unity/Session/dbusunitysessionservice.h'
413--- plugins/Unity/Session/dbusunitysessionservice.h 2016-06-22 13:38:16 +0000
414+++ plugins/Unity/Session/dbusunitysessionservice.h 2016-11-22 09:36:12 +0000
415@@ -1,5 +1,5 @@
416 /*
417- * Copyright (C) 2014, 2015 Canonical, Ltd.
418+ * Copyright (C) 2014-2016 Canonical, Ltd.
419 *
420 * This program is free software: you can redistribute it and/or modify it under
421 * the terms of the GNU Lesser General Public License version 3, as published by
422@@ -17,6 +17,7 @@
423 #ifndef DBUSUNITYSESSIONSERVICE_H
424 #define DBUSUNITYSESSIONSERVICE_H
425
426+#include <QDBusContext>
427 #include <QDBusObjectPath>
428
429 #include "unitydbusobject.h"
430@@ -36,6 +37,12 @@
431 Q_OBJECT
432 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.Session")
433
434+ /**
435+ * List of PIDs allowed to request screen inhibition
436+ */
437+ Q_PROPERTY(QStringList screenInhibitionsWhitelist READ screenInhibitionsWhitelist WRITE setScreenInhibitionsWhitelist
438+ NOTIFY screenInhibitionsWhitelistChanged)
439+
440 public:
441 DBusUnitySessionService();
442 ~DBusUnitySessionService() = default;
443@@ -48,6 +55,10 @@
444
445 // TODO: remove duplicate signals and split D-Bus and QML API's
446 // Apparently QML needs the signals in lowercase, while DBUS spec needs the uppercase version
447+
448+ QStringList screenInhibitionsWhitelist() const;
449+ void setScreenInhibitionsWhitelist(const QStringList &screenInhibitionsWhitelist);
450+
451 Q_SIGNALS:
452 /**
453 * LogoutRequested signal
454@@ -108,6 +119,8 @@
455 Q_SCRIPTABLE void Unlocked();
456 void unlocked();
457
458+ void screenInhibitionsWhitelistChanged();
459+
460 public Q_SLOTS:
461 /**
462 * Logout the system.
463@@ -313,13 +326,16 @@
464 */
465 Q_SCRIPTABLE quint32 GetActiveTime() const;
466
467+ /**
468+ * Simulate user activity, thus interrupting the screensaver
469+ */
470 Q_SCRIPTABLE void SimulateUserActivity();
471
472 Q_SIGNALS:
473 void ActiveChanged(bool active);
474 };
475
476-class DBusScreensaverWrapper: public UnityDBusObject
477+class DBusScreensaverWrapper: public UnityDBusObject, protected QDBusContext
478 {
479 Q_OBJECT
480 Q_CLASSINFO("D-Bus Interface", "org.freedesktop.ScreenSaver")
481@@ -354,8 +370,27 @@
482 */
483 Q_SCRIPTABLE quint32 GetSessionIdleTime() const;
484
485+ /**
486+ * Simulate user activity, thus interrupting the screensaver
487+ */
488 Q_SCRIPTABLE void SimulateUserActivity();
489
490+ /**
491+ * Inhibit idleness (ie screen blanking) for the caller application.
492+ *
493+ * @param appName A unique identifier for the application, usually a reverse domain (such as 'org.freedesktop.example').
494+ * @param reason A human-readable and possibly translated string explaining the reason why idleness is inhibited (such as 'Playing a movie').
495+ * @return A cookie uniquely representing the inhibition request, to be passed to UnInhibit when done; 0 in case of error
496+ */
497+ Q_SCRIPTABLE uint Inhibit(const QString &appName, const QString &reason);
498+
499+ /**
500+ * Disable inhibit idleness for the caller application.
501+ *
502+ * @param cookie A cookie representing the inhibition request, as returned by the 'Inhibit' function.
503+ */
504+ Q_SCRIPTABLE void UnInhibit(uint cookie);
505+
506 Q_SIGNALS:
507 void ActiveChanged(bool active);
508 };
509
510=== modified file 'qml/Components/Dialogs.qml'
511--- qml/Components/Dialogs.qml 2016-07-15 19:37:39 +0000
512+++ qml/Components/Dialogs.qml 2016-11-22 09:36:12 +0000
513@@ -112,12 +112,12 @@
514
515 GlobalShortcut { // lock screen
516 shortcut: Qt.Key_ScreenSaver
517- onTriggered: LightDMService.greeter.showGreeter()
518+ onTriggered: root.unitySessionService.PromptLock()
519 }
520
521 GlobalShortcut { // lock screen
522 shortcut: Qt.ControlModifier|Qt.AltModifier|Qt.Key_L
523- onTriggered: LightDMService.greeter.showGreeter()
524+ onTriggered: root.unitySessionService.PromptLock()
525 }
526
527 QtObject {
528@@ -151,7 +151,7 @@
529 Button {
530 text: i18n.ctr("Button: Lock the system", "Lock")
531 onClicked: {
532- LightDMService.greeter.showGreeter()
533+ root.unitySessionService.PromptLock()
534 logoutDialog.hide();
535 }
536 }
537
538=== modified file 'qml/Shell.qml'
539--- qml/Shell.qml 2016-11-09 15:07:26 +0000
540+++ qml/Shell.qml 2016-11-22 09:36:12 +0000
541@@ -375,15 +375,6 @@
542 }
543 }
544
545- Timer {
546- // See powerConnection for why this is useful
547- id: showGreeterDelayed
548- interval: 1
549- onTriggered: {
550- greeter.forceShow();
551- }
552- }
553-
554 Connections {
555 id: callConnection
556 target: callManager
557@@ -410,16 +401,7 @@
558 onStatusChanged: {
559 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
560 !callManager.hasCalls && !wizard.active) {
561- // We don't want to simply call greeter.showNow() here, because
562- // that will take too long. Qt will delay button event
563- // handling until the greeter is done loading and may think the
564- // user held down the power button the whole time, leading to a
565- // power dialog being shown. Instead, delay showing the
566- // greeter until we've finished handling the event. We could
567- // make the greeter load asynchronously instead, but that
568- // introduces a whole host of timing issues, especially with
569- // its animations. So this is simpler.
570- showGreeterDelayed.start();
571+ DBusUnitySessionService.PromptLock();
572 }
573 }
574 }
575
576=== modified file 'qml/Stage/Stage.qml'
577--- qml/Stage/Stage.qml 2016-11-12 16:05:40 +0000
578+++ qml/Stage/Stage.qml 2016-11-22 09:36:12 +0000
579@@ -17,6 +17,7 @@
580 import QtQuick 2.4
581 import Ubuntu.Components 1.3
582 import Unity.Application 0.1
583+import Unity.Session 0.1
584 import "../Components/PanelState"
585 import "../Components"
586 import Utils 0.1
587@@ -346,6 +347,31 @@
588 }
589
590 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
591+
592+ function updateScreenInhibitionsWhiteList() {
593+ var result = [];
594+ if (root.state == "staged" && priv.mainStageDelegate) {
595+ result.push(priv.mainStageDelegate.appId);
596+ } else if (root.state == "stagedWithSideStage") {
597+ if (priv.mainStageDelegate) {
598+ result.push(priv.mainStageDelegate.appId);
599+ }
600+ if (priv.sideStageDelegate) {
601+ result.push(priv.sideStageDelegate.appId);
602+ }
603+ } else if (root.state == "windowed") {
604+ for (var i = 0; i < appRepeater.count; i++) {
605+ var appDelegate = appRepeater.itemAt(i);
606+ if (appDelegate && !appDelegate.minimized) {
607+ result.push(appDelegate.appId);
608+ }
609+ }
610+ }
611+
612+ print("!!! Inhibition whitelist updated:", result);
613+
614+ DBusUnitySessionService.screenInhibitionsWhitelist = result;
615+ }
616 }
617
618 Component.onCompleted: priv.updateMainAndSideStageIndexes();
619@@ -521,9 +547,16 @@
620 },
621 Transition {
622 to: "stagedWithSideStage"
623- ScriptAction { script: priv.updateMainAndSideStageIndexes(); }
624+ ScriptAction { script: { priv.updateMainAndSideStageIndexes(); priv.updateScreenInhibitionsWhiteList(); }}
625+ },
626+ Transition {
627+ to: "staged"
628+ ScriptAction { script: priv.updateScreenInhibitionsWhiteList(); }
629+ },
630+ Transition {
631+ to: "windowed"
632+ ScriptAction { script: priv.updateScreenInhibitionsWhiteList(); }
633 }
634-
635 ]
636
637 MouseArea {
638@@ -571,10 +604,12 @@
639
640 Connections {
641 target: root.topLevelSurfaceList
642- onListChanged: priv.updateMainAndSideStageIndexes()
643+ onListChanged: {
644+ priv.updateMainAndSideStageIndexes();
645+ priv.updateScreenInhibitionsWhiteList();
646+ }
647 }
648
649-
650 DropArea {
651 objectName: "MainStageDropArea"
652 anchors {
653
654=== modified file 'src/libunity8-private/unitydbusobject.cpp'
655--- src/libunity8-private/unitydbusobject.cpp 2015-09-14 09:11:08 +0000
656+++ src/libunity8-private/unitydbusobject.cpp 2016-11-22 09:36:12 +0000
657@@ -42,11 +42,6 @@
658 m_connection.unregisterObject(path());
659 }
660
661-QDBusConnection UnityDBusObject::connection() const
662-{
663- return m_connection;
664-}
665-
666 QString UnityDBusObject::path() const
667 {
668 return m_path;
669@@ -70,7 +65,7 @@
670 message << changedProps;
671 message << QStringList();
672
673- connection().send(message);
674+ m_connection.send(message);
675 }
676
677 void UnityDBusObject::registerObject()
678
679=== modified file 'src/libunity8-private/unitydbusobject.h'
680--- src/libunity8-private/unitydbusobject.h 2014-10-09 21:29:00 +0000
681+++ src/libunity8-private/unitydbusobject.h 2016-11-22 09:36:12 +0000
682@@ -28,7 +28,6 @@
683 explicit UnityDBusObject(const QString &path, const QString &service = QString(), bool async = true, QObject *parent = 0);
684 ~UnityDBusObject();
685
686- QDBusConnection connection() const;
687 QString path() const;
688
689 protected:
690
691=== modified file 'tests/plugins/Unity/Session/CMakeLists.txt'
692--- tests/plugins/Unity/Session/CMakeLists.txt 2016-06-21 14:23:49 +0000
693+++ tests/plugins/Unity/Session/CMakeLists.txt 2016-11-22 09:36:12 +0000
694@@ -13,6 +13,7 @@
695 ${CMAKE_SOURCE_DIR}/plugins/Unity/Session
696 ${libunity8-private_SOURCE_DIR}
697 ${GLIB_INCLUDE_DIRS}
698+ ${UAL_INCLUDE_DIRS}
699 )
700
701 add_definitions(-DSM_BUSNAME=sessionBus)
702@@ -38,6 +39,7 @@
703 target_link_libraries(sessionbackendtestExec
704 unity8-private
705 ${GLIB_LIBRARIES}
706+ ${UAL_LIBRARIES}
707 )
708 qt5_use_modules(sessionbackendtestExec Test Core Qml DBus)
709
710
711=== modified file 'tests/plugins/Unity/Session/LogindServer.h'
712--- tests/plugins/Unity/Session/LogindServer.h 2016-06-22 13:38:16 +0000
713+++ tests/plugins/Unity/Session/LogindServer.h 2016-11-22 09:36:12 +0000
714@@ -37,7 +37,7 @@
715 Q_SIGNALS:
716 void Lock();
717 void Unlock();
718- void PrepareForSleep();
719+ void PrepareForSleep(bool);
720 };
721
722 #endif

Subscribers

People subscribed via source and target branches