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
=== modified file 'plugins/Unity/Session/CMakeLists.txt'
--- plugins/Unity/Session/CMakeLists.txt 2016-06-21 14:23:49 +0000
+++ plugins/Unity/Session/CMakeLists.txt 2016-11-22 09:36:12 +0000
@@ -3,6 +3,7 @@
3 ${CMAKE_CURRENT_BINARY_DIR}3 ${CMAKE_CURRENT_BINARY_DIR}
4 ${GIO_INCLUDE_DIRS}4 ${GIO_INCLUDE_DIRS}
5 ${GLIB_INCLUDE_DIRS}5 ${GLIB_INCLUDE_DIRS}
6 ${UAL_INCLUDE_DIRS}
6 ${libunity8-private_SOURCE_DIR}7 ${libunity8-private_SOURCE_DIR}
7)8)
89
@@ -23,6 +24,7 @@
23 unity8-private24 unity8-private
24 ${GIO_LDFLAGS}25 ${GIO_LDFLAGS}
25 ${GLIB_LIBRARIES}26 ${GLIB_LIBRARIES}
27 ${UAL_LIBRARIES}
26 )28 )
2729
28# export the qmldir and qmltypes files30# export the qmldir and qmltypes files
2931
=== modified file 'plugins/Unity/Session/dbusunitysessionservice.cpp'
--- plugins/Unity/Session/dbusunitysessionservice.cpp 2016-06-22 13:38:16 +0000
+++ plugins/Unity/Session/dbusunitysessionservice.cpp 2016-11-22 09:36:12 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2014, 2015 Canonical, Ltd.2 * Copyright (C) 2014-2016 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -21,6 +21,7 @@
21#include <sys/types.h>21#include <sys/types.h>
22#include <unistd.h>22#include <unistd.h>
23#include <pwd.h>23#include <pwd.h>
24#include <algorithm>
2425
25// Qt26// Qt
26#include <QDebug>27#include <QDebug>
@@ -29,6 +30,14 @@
29#include <QElapsedTimer>30#include <QElapsedTimer>
30#include <QDateTime>31#include <QDateTime>
31#include <QDBusUnixFileDescriptor>32#include <QDBusUnixFileDescriptor>
33#include <QDBusServiceWatcher>
34#include <QDBusConnectionInterface>
35#include <QPointer>
36
37// ual
38#include <ubuntu-app-launch/appid.h>
39#include <ubuntu-app-launch/application.h>
40#include <ubuntu-app-launch/registry.h>
3241
33// Glib42// Glib
34#include <glib.h>43#include <glib.h>
@@ -41,16 +50,39 @@
41#define ACTIVE_KEY QStringLiteral("Active")50#define ACTIVE_KEY QStringLiteral("Active")
42#define IDLE_SINCE_KEY QStringLiteral("IdleSinceHint")51#define IDLE_SINCE_KEY QStringLiteral("IdleSinceHint")
4352
53#define UNITY_SCREEN_SERVICE QStringLiteral("com.canonical.Unity.Screen")
54#define UNITY_SCREEN_PATH QStringLiteral("/com/canonical/Unity/Screen")
55#define UNITY_SCREEN_IFACE QStringLiteral("com.canonical.Unity.Screen")
56
57namespace ual = ubuntu::app_launch;
58
59struct InhibitionInfo {
60 int cookie{0};
61 QString dbusAppName;
62 QString dbusReason;
63 QString dbusService;
64 pid_t pid{0};
65};
66
44class DBusUnitySessionServicePrivate: public QObject67class DBusUnitySessionServicePrivate: public QObject
45{68{
46 Q_OBJECT69 Q_OBJECT
47public:70public:
48 QString logindSessionPath;71 QString logindSessionPath;
49 bool isSessionActive = true;72 bool isSessionActive{true};
50 QElapsedTimer screensaverActiveTimer;73 QElapsedTimer screensaverActiveTimer;
51 QDBusUnixFileDescriptor m_systemdInhibitFd;74 QDBusUnixFileDescriptor m_systemdInhibitFd;
5275
53 DBusUnitySessionServicePrivate(): QObject() {76 // inhibit stuff
77 QPointer<QDBusServiceWatcher> busWatcher;
78 std::list<InhibitionInfo> inhibitions;
79 QStringList screenInhibitionsWhitelist; // list of appIds
80 std::shared_ptr<ual::Registry> m_ualRegistry{std::make_shared<ual::Registry>()};
81
82 DBusUnitySessionServicePrivate():
83 QObject()
84 , busWatcher(new QDBusServiceWatcher(this))
85 {
54 init();86 init();
55 checkActive();87 checkActive();
56 }88 }
@@ -80,6 +112,11 @@
80 } else {112 } else {
81 qWarning() << "Failed to get logind session path" << reply.error().message();113 qWarning() << "Failed to get logind session path" << reply.error().message();
82 }114 }
115
116 // watch services
117 busWatcher->setConnection(QDBusConnection::sessionBus());
118 busWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
119 connect(busWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &DBusUnitySessionServicePrivate::onServiceUnregistered);
83 }120 }
84121
85 void setupSystemdInhibition()122 void setupSystemdInhibition()
@@ -128,6 +165,7 @@
128 QDBusConnection::SM_BUSNAME().asyncCall(msg);165 QDBusConnection::SM_BUSNAME().asyncCall(msg);
129 }166 }
130167
168 // set the session as active or inactive
131 void setActive(bool active)169 void setActive(bool active)
132 {170 {
133 isSessionActive = active;171 isSessionActive = active;
@@ -211,6 +249,139 @@
211 QDBusConnection::SM_BUSNAME().asyncCall(msg);249 QDBusConnection::SM_BUSNAME().asyncCall(msg);
212 }250 }
213251
252 /**
253 * Register inhibition, enable it if on whitelist
254 *
255 * @return the inhibition cookie, or 0 if the call didn't succeed
256 */
257 int addInhibition(const QString &service, int pid, const QString &appName, const QString &reason)
258 {
259 InhibitionInfo inh;
260 inh.dbusAppName = appName;
261 inh.dbusReason = reason;
262 inh.dbusService = service;
263 inh.pid = static_cast<pid_t>(pid);
264
265 int cookie = 0;
266
267 if (whiteListCheck(pid)) {
268 cookie = addInhibitionHelper();
269 if (cookie > 0) {
270 inh.cookie = cookie;
271 }
272 } else
273 qDebug() << "!!! Whitelist doesn't contain pid:" << pid << screenInhibitionsWhitelist;
274
275 if (!busWatcher.isNull() && !service.isEmpty() && !busWatcher->watchedServices().contains(service)) {
276 qDebug() << "!!! Started watching service:" << service;
277 busWatcher->addWatchedService(service);
278 }
279
280 qDebug() << "!!! addInhibition, cookie:" << cookie;
281
282 inhibitions.push_back(inh);
283 return cookie;
284 }
285
286 /**
287 * Ask repowerd to keep the display on (enable the inhibition), start watching the service
288 * @return cookie, 0 in failure
289 */
290 int addInhibitionHelper()
291 {
292 QDBusMessage msg = QDBusMessage::createMethodCall(UNITY_SCREEN_SERVICE, UNITY_SCREEN_PATH, UNITY_SCREEN_IFACE, QStringLiteral("keepDisplayOn"));
293 QDBusReply<int> cookie = QDBusConnection::SM_BUSNAME().call(msg);
294 if (cookie.isValid()) {
295 return cookie;
296 } else {
297 qWarning() << "Failed to inhibit screen blanking" << cookie.error().message();
298 }
299
300 return 0;
301 }
302
303 /**
304 * Release the repowerd screen inhibition based on @p cookie
305 */
306 void removeInhibition(int cookie)
307 {
308 qDebug() << "!!! removeInhibition, cookie:" << cookie;
309 QDBusMessage msg = QDBusMessage::createMethodCall(UNITY_SCREEN_SERVICE, UNITY_SCREEN_PATH, UNITY_SCREEN_IFACE, QStringLiteral("removeDisplayOnRequest"));
310 msg << cookie;
311 QDBusReply<void> reply = QDBusConnection::SM_BUSNAME().call(msg);
312 if (!reply.isValid()) {
313 qWarning() << "Failed to release screen blanking inhibition" << reply.error().message();
314 }
315 }
316
317 /**
318 * Drop the inhibition from the list with the matching @p cookie, cleaning up the bus watcher as well if needed
319 */
320 void removeInhibitionHelper(int cookie)
321 {
322 qDebug() << "!!! removeInhibitionHelper, cookie:" << cookie;
323 // drop the inhibition from the list with the matching cookie
324 QString service;
325 inhibitions.remove_if([&service, cookie](const InhibitionInfo & inh) {service = inh.dbusService; return inh.cookie == cookie;});
326
327 qDebug() << "!!! Removed inhibition for service?:" << service;
328
329 if (!busWatcher.isNull() && std::none_of(inhibitions.cbegin(), inhibitions.cend(),
330 [service](const InhibitionInfo & inh){return inh.dbusService == service;})) {
331 // no cookies from service left
332 qDebug() << "!!! Stopped watching service:" << service;
333 busWatcher->removeWatchedService(service);
334 }
335 }
336
337 /**
338 * Enable/disable inhibitions dynamically as the whitelist changes
339 */
340 void updateInhibitions()
341 {
342 qDebug() << "!!! Update inhibitions, empty?" << inhibitions.empty();
343 if (inhibitions.empty()) // no inhibitions set up, bail out
344 return;
345
346 qDebug() << "!!! Update inhibitions, whitelist of PIDs:" << screenInhibitionsWhitelist;
347
348 for (InhibitionInfo inh: inhibitions) {
349 if (!whiteListCheck(inh.pid)) { // not on whitelist anymore, disable temporarily
350 qDebug() << "!!! Disabling inhibition, not on whitelist:" << inh.dbusService;
351 removeInhibition(inh.cookie);
352 inh.cookie = 0; // reset the cookie
353 } else if (whiteListCheck(inh.pid) && inh.cookie == 0) { // on whitelist but not enabled
354 qDebug() << "!!! Enabling inhibition, on whitelist but not enabled:" << inh.dbusService;
355 inh.cookie = addInhibitionHelper();
356 }
357 }
358 }
359
360 bool whiteListCheck(pid_t pid) const {
361 Q_FOREACH(const QString &appId, screenInhibitionsWhitelist) {
362 ual::AppID ualAppId = ual::AppID::find(m_ualRegistry, appId.toStdString());
363 if (ualAppId.empty()) {
364 continue;
365 }
366
367 std::shared_ptr<ual::Application> ualApp;
368 try {
369 ualApp = ual::Application::create(ualAppId, m_ualRegistry);
370 }
371 catch (std::runtime_error &e) {
372 qWarning() << "Couldn't find UAL application object for" << appId << "-" << e.what();
373 continue;
374 }
375 if (ualApp) {
376 if (std::any_of(ualApp->instances().cbegin(), ualApp->instances().cend(),
377 [pid](const std::shared_ptr<ual::Application::Instance> &inst){ return inst && inst->hasPid(pid); })) {
378 return true;
379 }
380 }
381 }
382 return false;
383 }
384
214private Q_SLOTS:385private Q_SLOTS:
215 void onPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps)386 void onPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps)
216 {387 {
@@ -232,6 +403,19 @@
232 }403 }
233 }404 }
234405
406 void onServiceUnregistered(const QString &service)
407 {
408 // cleanup inhibitions
409 qDebug() << "!!! Cleanup inhibitions";
410 Q_FOREACH(InhibitionInfo inh, inhibitions) {
411 if (inh.dbusService == service) {
412 qDebug() << "!!! Cleaning up cookie" << inh.cookie << ", after service:" << inh.dbusService;
413 removeInhibition(inh.cookie);
414 removeInhibitionHelper(inh.cookie);
415 }
416 }
417 }
418
235Q_SIGNALS:419Q_SIGNALS:
236 void screensaverActiveChanged(bool active);420 void screensaverActiveChanged(bool active);
237 void prepareForSleep();421 void prepareForSleep();
@@ -245,7 +429,7 @@
245 if (!d->logindSessionPath.isEmpty()) {429 if (!d->logindSessionPath.isEmpty()) {
246 // connect our PromptLock() slot to the logind's session Lock() signal430 // connect our PromptLock() slot to the logind's session Lock() signal
247 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Lock"), this, SLOT(PromptLock()));431 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Lock"), this, SLOT(PromptLock()));
248 // ... and our Unlocked() signal to the logind's session Unlock() signal432 // ... and our doUnlock() slot to the logind's session Unlock() signal
249 // (lightdm handles the unlocking by calling logind's Unlock method which in turn emits this signal we connect to)433 // (lightdm handles the unlocking by calling logind's Unlock method which in turn emits this signal we connect to)
250 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Unlock"), this, SLOT(doUnlock()));434 QDBusConnection::SM_BUSNAME().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Unlock"), this, SLOT(doUnlock()));
251 connect(d, &DBusUnitySessionServicePrivate::prepareForSleep, this, &DBusUnitySessionService::PromptLock);435 connect(d, &DBusUnitySessionServicePrivate::prepareForSleep, this, &DBusUnitySessionService::PromptLock);
@@ -254,6 +438,22 @@
254 }438 }
255}439}
256440
441QStringList DBusUnitySessionService::screenInhibitionsWhitelist() const
442{
443 return d->screenInhibitionsWhitelist;
444}
445
446void DBusUnitySessionService::setScreenInhibitionsWhitelist(const QStringList &screenInhibitionsWhitelist)
447{
448 qDebug() << "!!! Update whitelist, new one:" << screenInhibitionsWhitelist << ", old one:" << d->screenInhibitionsWhitelist;
449 if (std::is_permutation(screenInhibitionsWhitelist.begin(), screenInhibitionsWhitelist.end(), d->screenInhibitionsWhitelist.begin()))
450 return;
451
452 d->screenInhibitionsWhitelist = screenInhibitionsWhitelist;
453 Q_EMIT screenInhibitionsWhitelistChanged();
454 d->updateInhibitions();
455}
456
257void DBusUnitySessionService::Logout()457void DBusUnitySessionService::Logout()
258{458{
259 // TODO ask the apps to quit and then emit the signal459 // TODO ask the apps to quit and then emit the signal
@@ -263,11 +463,11 @@
263463
264void DBusUnitySessionService::EndSession()464void DBusUnitySessionService::EndSession()
265{465{
266 const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("com.ubuntu.Upstart"),466 const QDBusMessage msg = QDBusMessage::createMethodCall(LOGIN1_SERVICE,
267 QStringLiteral("/com/ubuntu/Upstart"),467 d->logindSessionPath,
268 QStringLiteral("com.ubuntu.Upstart0_6"),468 LOGIN1_SESSION_IFACE,
269 QStringLiteral("EndSession"));469 QStringLiteral("Terminate"));
270 QDBusConnection::sessionBus().asyncCall(msg);470 QDBusConnection::SM_BUSNAME().asyncCall(msg);
271}471}
272472
273bool DBusUnitySessionService::CanHibernate() const473bool DBusUnitySessionService::CanHibernate() const
@@ -307,27 +507,12 @@
307507
308QString DBusUnitySessionService::RealName() const508QString DBusUnitySessionService::RealName() const
309{509{
310 struct passwd *p = getpwuid(geteuid());510 return QString::fromUtf8(g_get_real_name());
311 if (p) {
312 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
313 if (!gecos.isEmpty()) {
314 const QStringList splitGecos = gecos.split(QLatin1Char(','));
315 return splitGecos.first();
316 }
317 }
318
319 return QString();
320}511}
321512
322QString DBusUnitySessionService::HostName() const513QString DBusUnitySessionService::HostName() const
323{514{
324 char hostName[512];515 return QString::fromUtf8(g_get_host_name());
325 if (gethostname(hostName, sizeof(hostName)) == -1) {
326 qWarning() << "Could not determine local hostname";
327 return QString();
328 }
329 hostName[sizeof(hostName) - 1] = '\0';
330 return QString::fromLocal8Bit(hostName);
331}516}
332517
333void DBusUnitySessionService::PromptLock()518void DBusUnitySessionService::PromptLock()
@@ -337,6 +522,7 @@
337 // user session.522 // user session.
338 Q_EMIT LockRequested();523 Q_EMIT LockRequested();
339 Q_EMIT lockRequested();524 Q_EMIT lockRequested();
525 d->setActive(false);
340}526}
341527
342void DBusUnitySessionService::Lock()528void DBusUnitySessionService::Lock()
@@ -395,6 +581,7 @@
395{581{
396 Q_EMIT Unlocked();582 Q_EMIT Unlocked();
397 Q_EMIT unlocked();583 Q_EMIT unlocked();
584 d->setActive(true);
398}585}
399586
400bool DBusUnitySessionService::IsLocked() const587bool DBusUnitySessionService::IsLocked() const
@@ -528,7 +715,7 @@
528715
529void DBusGnomeScreensaverWrapper::SimulateUserActivity()716void DBusGnomeScreensaverWrapper::SimulateUserActivity()
530{717{
531 d->setIdleHint(false);718 d->setActive(true);
532}719}
533720
534721
@@ -570,7 +757,29 @@
570757
571void DBusScreensaverWrapper::SimulateUserActivity()758void DBusScreensaverWrapper::SimulateUserActivity()
572{759{
573 d->setIdleHint(false);760 d->setActive(true);
761}
762
763uint DBusScreensaverWrapper::Inhibit(const QString &appName, const QString &reason)
764{
765 QString service;
766 int pid = 0;
767 if (calledFromDBus()) {
768 service = message().service();
769 pid = connection().interface()->servicePid(service);
770 }
771 qDebug() << "!!! INHIBIT (appName, reason, dbusService, pid)" << appName << reason << service << pid;
772 uint cookie = static_cast<uint>(d->addInhibition(service, pid, appName, reason));
773 d->checkActive();
774 return cookie;
775}
776
777void DBusScreensaverWrapper::UnInhibit(uint cookie)
778{
779 qDebug() << "!!! UNINHIBIT (cookie)" << cookie;
780 d->removeInhibition(cookie);
781 d->removeInhibitionHelper(cookie);
782 d->checkActive();
574}783}
575784
576#include "dbusunitysessionservice.moc"785#include "dbusunitysessionservice.moc"
577786
=== modified file 'plugins/Unity/Session/dbusunitysessionservice.h'
--- plugins/Unity/Session/dbusunitysessionservice.h 2016-06-22 13:38:16 +0000
+++ plugins/Unity/Session/dbusunitysessionservice.h 2016-11-22 09:36:12 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2014, 2015 Canonical, Ltd.2 * Copyright (C) 2014-2016 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -17,6 +17,7 @@
17#ifndef DBUSUNITYSESSIONSERVICE_H17#ifndef DBUSUNITYSESSIONSERVICE_H
18#define DBUSUNITYSESSIONSERVICE_H18#define DBUSUNITYSESSIONSERVICE_H
1919
20#include <QDBusContext>
20#include <QDBusObjectPath>21#include <QDBusObjectPath>
2122
22#include "unitydbusobject.h"23#include "unitydbusobject.h"
@@ -36,6 +37,12 @@
36 Q_OBJECT37 Q_OBJECT
37 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.Session")38 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.Session")
3839
40 /**
41 * List of PIDs allowed to request screen inhibition
42 */
43 Q_PROPERTY(QStringList screenInhibitionsWhitelist READ screenInhibitionsWhitelist WRITE setScreenInhibitionsWhitelist
44 NOTIFY screenInhibitionsWhitelistChanged)
45
39public:46public:
40 DBusUnitySessionService();47 DBusUnitySessionService();
41 ~DBusUnitySessionService() = default;48 ~DBusUnitySessionService() = default;
@@ -48,6 +55,10 @@
4855
49 // TODO: remove duplicate signals and split D-Bus and QML API's56 // TODO: remove duplicate signals and split D-Bus and QML API's
50 // Apparently QML needs the signals in lowercase, while DBUS spec needs the uppercase version57 // Apparently QML needs the signals in lowercase, while DBUS spec needs the uppercase version
58
59 QStringList screenInhibitionsWhitelist() const;
60 void setScreenInhibitionsWhitelist(const QStringList &screenInhibitionsWhitelist);
61
51Q_SIGNALS:62Q_SIGNALS:
52 /**63 /**
53 * LogoutRequested signal64 * LogoutRequested signal
@@ -108,6 +119,8 @@
108 Q_SCRIPTABLE void Unlocked();119 Q_SCRIPTABLE void Unlocked();
109 void unlocked();120 void unlocked();
110121
122 void screenInhibitionsWhitelistChanged();
123
111public Q_SLOTS:124public Q_SLOTS:
112 /**125 /**
113 * Logout the system.126 * Logout the system.
@@ -313,13 +326,16 @@
313 */326 */
314 Q_SCRIPTABLE quint32 GetActiveTime() const;327 Q_SCRIPTABLE quint32 GetActiveTime() const;
315328
329 /**
330 * Simulate user activity, thus interrupting the screensaver
331 */
316 Q_SCRIPTABLE void SimulateUserActivity();332 Q_SCRIPTABLE void SimulateUserActivity();
317333
318Q_SIGNALS:334Q_SIGNALS:
319 void ActiveChanged(bool active);335 void ActiveChanged(bool active);
320};336};
321337
322class DBusScreensaverWrapper: public UnityDBusObject338class DBusScreensaverWrapper: public UnityDBusObject, protected QDBusContext
323{339{
324 Q_OBJECT340 Q_OBJECT
325 Q_CLASSINFO("D-Bus Interface", "org.freedesktop.ScreenSaver")341 Q_CLASSINFO("D-Bus Interface", "org.freedesktop.ScreenSaver")
@@ -354,8 +370,27 @@
354 */370 */
355 Q_SCRIPTABLE quint32 GetSessionIdleTime() const;371 Q_SCRIPTABLE quint32 GetSessionIdleTime() const;
356372
373 /**
374 * Simulate user activity, thus interrupting the screensaver
375 */
357 Q_SCRIPTABLE void SimulateUserActivity();376 Q_SCRIPTABLE void SimulateUserActivity();
358377
378 /**
379 * Inhibit idleness (ie screen blanking) for the caller application.
380 *
381 * @param appName A unique identifier for the application, usually a reverse domain (such as 'org.freedesktop.example').
382 * @param reason A human-readable and possibly translated string explaining the reason why idleness is inhibited (such as 'Playing a movie').
383 * @return A cookie uniquely representing the inhibition request, to be passed to UnInhibit when done; 0 in case of error
384 */
385 Q_SCRIPTABLE uint Inhibit(const QString &appName, const QString &reason);
386
387 /**
388 * Disable inhibit idleness for the caller application.
389 *
390 * @param cookie A cookie representing the inhibition request, as returned by the 'Inhibit' function.
391 */
392 Q_SCRIPTABLE void UnInhibit(uint cookie);
393
359Q_SIGNALS:394Q_SIGNALS:
360 void ActiveChanged(bool active);395 void ActiveChanged(bool active);
361};396};
362397
=== modified file 'qml/Components/Dialogs.qml'
--- qml/Components/Dialogs.qml 2016-07-15 19:37:39 +0000
+++ qml/Components/Dialogs.qml 2016-11-22 09:36:12 +0000
@@ -112,12 +112,12 @@
112112
113 GlobalShortcut { // lock screen113 GlobalShortcut { // lock screen
114 shortcut: Qt.Key_ScreenSaver114 shortcut: Qt.Key_ScreenSaver
115 onTriggered: LightDMService.greeter.showGreeter()115 onTriggered: root.unitySessionService.PromptLock()
116 }116 }
117117
118 GlobalShortcut { // lock screen118 GlobalShortcut { // lock screen
119 shortcut: Qt.ControlModifier|Qt.AltModifier|Qt.Key_L119 shortcut: Qt.ControlModifier|Qt.AltModifier|Qt.Key_L
120 onTriggered: LightDMService.greeter.showGreeter()120 onTriggered: root.unitySessionService.PromptLock()
121 }121 }
122122
123 QtObject {123 QtObject {
@@ -151,7 +151,7 @@
151 Button {151 Button {
152 text: i18n.ctr("Button: Lock the system", "Lock")152 text: i18n.ctr("Button: Lock the system", "Lock")
153 onClicked: {153 onClicked: {
154 LightDMService.greeter.showGreeter()154 root.unitySessionService.PromptLock()
155 logoutDialog.hide();155 logoutDialog.hide();
156 }156 }
157 }157 }
158158
=== modified file 'qml/Shell.qml'
--- qml/Shell.qml 2016-11-09 15:07:26 +0000
+++ qml/Shell.qml 2016-11-22 09:36:12 +0000
@@ -375,15 +375,6 @@
375 }375 }
376 }376 }
377377
378 Timer {
379 // See powerConnection for why this is useful
380 id: showGreeterDelayed
381 interval: 1
382 onTriggered: {
383 greeter.forceShow();
384 }
385 }
386
387 Connections {378 Connections {
388 id: callConnection379 id: callConnection
389 target: callManager380 target: callManager
@@ -410,16 +401,7 @@
410 onStatusChanged: {401 onStatusChanged: {
411 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&402 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
412 !callManager.hasCalls && !wizard.active) {403 !callManager.hasCalls && !wizard.active) {
413 // We don't want to simply call greeter.showNow() here, because404 DBusUnitySessionService.PromptLock();
414 // that will take too long. Qt will delay button event
415 // handling until the greeter is done loading and may think the
416 // user held down the power button the whole time, leading to a
417 // power dialog being shown. Instead, delay showing the
418 // greeter until we've finished handling the event. We could
419 // make the greeter load asynchronously instead, but that
420 // introduces a whole host of timing issues, especially with
421 // its animations. So this is simpler.
422 showGreeterDelayed.start();
423 }405 }
424 }406 }
425 }407 }
426408
=== modified file 'qml/Stage/Stage.qml'
--- qml/Stage/Stage.qml 2016-11-12 16:05:40 +0000
+++ qml/Stage/Stage.qml 2016-11-22 09:36:12 +0000
@@ -17,6 +17,7 @@
17import QtQuick 2.417import QtQuick 2.4
18import Ubuntu.Components 1.318import Ubuntu.Components 1.3
19import Unity.Application 0.119import Unity.Application 0.1
20import Unity.Session 0.1
20import "../Components/PanelState"21import "../Components/PanelState"
21import "../Components"22import "../Components"
22import Utils 0.123import Utils 0.1
@@ -346,6 +347,31 @@
346 }347 }
347348
348 readonly property real virtualKeyboardHeight: root.inputMethodRect.height349 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
350
351 function updateScreenInhibitionsWhiteList() {
352 var result = [];
353 if (root.state == "staged" && priv.mainStageDelegate) {
354 result.push(priv.mainStageDelegate.appId);
355 } else if (root.state == "stagedWithSideStage") {
356 if (priv.mainStageDelegate) {
357 result.push(priv.mainStageDelegate.appId);
358 }
359 if (priv.sideStageDelegate) {
360 result.push(priv.sideStageDelegate.appId);
361 }
362 } else if (root.state == "windowed") {
363 for (var i = 0; i < appRepeater.count; i++) {
364 var appDelegate = appRepeater.itemAt(i);
365 if (appDelegate && !appDelegate.minimized) {
366 result.push(appDelegate.appId);
367 }
368 }
369 }
370
371 print("!!! Inhibition whitelist updated:", result);
372
373 DBusUnitySessionService.screenInhibitionsWhitelist = result;
374 }
349 }375 }
350376
351 Component.onCompleted: priv.updateMainAndSideStageIndexes();377 Component.onCompleted: priv.updateMainAndSideStageIndexes();
@@ -521,9 +547,16 @@
521 },547 },
522 Transition {548 Transition {
523 to: "stagedWithSideStage"549 to: "stagedWithSideStage"
524 ScriptAction { script: priv.updateMainAndSideStageIndexes(); }550 ScriptAction { script: { priv.updateMainAndSideStageIndexes(); priv.updateScreenInhibitionsWhiteList(); }}
551 },
552 Transition {
553 to: "staged"
554 ScriptAction { script: priv.updateScreenInhibitionsWhiteList(); }
555 },
556 Transition {
557 to: "windowed"
558 ScriptAction { script: priv.updateScreenInhibitionsWhiteList(); }
525 }559 }
526
527 ]560 ]
528561
529 MouseArea {562 MouseArea {
@@ -571,10 +604,12 @@
571604
572 Connections {605 Connections {
573 target: root.topLevelSurfaceList606 target: root.topLevelSurfaceList
574 onListChanged: priv.updateMainAndSideStageIndexes()607 onListChanged: {
608 priv.updateMainAndSideStageIndexes();
609 priv.updateScreenInhibitionsWhiteList();
610 }
575 }611 }
576612
577
578 DropArea {613 DropArea {
579 objectName: "MainStageDropArea"614 objectName: "MainStageDropArea"
580 anchors {615 anchors {
581616
=== modified file 'src/libunity8-private/unitydbusobject.cpp'
--- src/libunity8-private/unitydbusobject.cpp 2015-09-14 09:11:08 +0000
+++ src/libunity8-private/unitydbusobject.cpp 2016-11-22 09:36:12 +0000
@@ -42,11 +42,6 @@
42 m_connection.unregisterObject(path());42 m_connection.unregisterObject(path());
43}43}
4444
45QDBusConnection UnityDBusObject::connection() const
46{
47 return m_connection;
48}
49
50QString UnityDBusObject::path() const45QString UnityDBusObject::path() const
51{46{
52 return m_path;47 return m_path;
@@ -70,7 +65,7 @@
70 message << changedProps;65 message << changedProps;
71 message << QStringList();66 message << QStringList();
7267
73 connection().send(message);68 m_connection.send(message);
74}69}
7570
76void UnityDBusObject::registerObject()71void UnityDBusObject::registerObject()
7772
=== modified file 'src/libunity8-private/unitydbusobject.h'
--- src/libunity8-private/unitydbusobject.h 2014-10-09 21:29:00 +0000
+++ src/libunity8-private/unitydbusobject.h 2016-11-22 09:36:12 +0000
@@ -28,7 +28,6 @@
28 explicit UnityDBusObject(const QString &path, const QString &service = QString(), bool async = true, QObject *parent = 0);28 explicit UnityDBusObject(const QString &path, const QString &service = QString(), bool async = true, QObject *parent = 0);
29 ~UnityDBusObject();29 ~UnityDBusObject();
3030
31 QDBusConnection connection() const;
32 QString path() const;31 QString path() const;
3332
34protected:33protected:
3534
=== modified file 'tests/plugins/Unity/Session/CMakeLists.txt'
--- tests/plugins/Unity/Session/CMakeLists.txt 2016-06-21 14:23:49 +0000
+++ tests/plugins/Unity/Session/CMakeLists.txt 2016-11-22 09:36:12 +0000
@@ -13,6 +13,7 @@
13 ${CMAKE_SOURCE_DIR}/plugins/Unity/Session13 ${CMAKE_SOURCE_DIR}/plugins/Unity/Session
14 ${libunity8-private_SOURCE_DIR}14 ${libunity8-private_SOURCE_DIR}
15 ${GLIB_INCLUDE_DIRS}15 ${GLIB_INCLUDE_DIRS}
16 ${UAL_INCLUDE_DIRS}
16)17)
1718
18add_definitions(-DSM_BUSNAME=sessionBus)19add_definitions(-DSM_BUSNAME=sessionBus)
@@ -38,6 +39,7 @@
38target_link_libraries(sessionbackendtestExec39target_link_libraries(sessionbackendtestExec
39 unity8-private40 unity8-private
40 ${GLIB_LIBRARIES}41 ${GLIB_LIBRARIES}
42 ${UAL_LIBRARIES}
41 )43 )
42qt5_use_modules(sessionbackendtestExec Test Core Qml DBus)44qt5_use_modules(sessionbackendtestExec Test Core Qml DBus)
4345
4446
=== modified file 'tests/plugins/Unity/Session/LogindServer.h'
--- tests/plugins/Unity/Session/LogindServer.h 2016-06-22 13:38:16 +0000
+++ tests/plugins/Unity/Session/LogindServer.h 2016-11-22 09:36:12 +0000
@@ -37,7 +37,7 @@
37Q_SIGNALS:37Q_SIGNALS:
38 void Lock();38 void Lock();
39 void Unlock();39 void Unlock();
40 void PrepareForSleep();40 void PrepareForSleep(bool);
41};41};
4242
43#endif43#endif

Subscribers

People subscribed via source and target branches