on xenial help sign in
Split the welcome screen into its own executable and allow it to be a proper LightDM greeter.
commit65045afad9e419bf2908536286f4c5cdf74f3916 authorMichael Terry <michael.terry@canonical.com> dateFri 30 May 2014, 09:28 (12 years ago) parent87a7900acf0ab7
122 files changed+2257−719
CMakeLists.txt+1 data/51-unity8-greeter.conf+2 data/CMakeLists.txt+13 data/unity8-greeter-init.conf+12 data/unity8-greeter-wrapper+98 data/unity8-greeter.desktop.in+5 debian/changelog+6 debian/control+16 debian/copyright+1−1 debian/rules−4 debian/unity8-greeter.install+6 debian/unity8-private.install+1 debian/unity8.install−1 plugins/AccountsService/AccountsService.cpp+34−11 plugins/AccountsService/AccountsService.h+9 plugins/CMakeLists.txt+1 plugins/LightDM/CMakeLists.txt+6−9 plugins/LightDM/Greeter.cpp+3 plugins/LightDM/Greeter.h+2 plugins/LightDM/URLDispatcher.cpp+55 plugins/LightDM/URLDispatcher.h+34 plugins/LightDM/plugin.cpp+9 plugins/SessionBroadcast/SessionBroadcast.cpp+35 plugins/SessionBroadcast/SessionBroadcast.h+11 plugins/SessionManager/CMakeLists.txt+22 plugins/SessionManager/SessionManager.cpp+124 plugins/SessionManager/SessionManager.h+61 plugins/SessionManager/plugin.cpp+35 plugins/SessionManager/plugin.h+35 plugins/SessionManager/qmldir+2 plugins/Unity/Launcher/backend/launcherbackend.cpp+16−2 plugins/Unity/Launcher/backend/launcherbackend.h+7−1 plugins/Unity/Launcher/launcheritem.cpp+14−9 plugins/Unity/Launcher/launcheritem.h+2−1 plugins/Unity/Launcher/launchermodel.cpp+41−11 plugins/Unity/Launcher/launchermodel.h+2 po/ug.po+2−1 qml/Components/BasicShell.qml+84 qml/Components/EdgeDemo.qml+1−53 qml/Greeter/Lockscreen.qml → qml/Components/Lockscreen.qml−20 qml/Components/PageHeader.qml+3−2 qml/Greeter/PassphraseLockscreen.qml → qml/Components/PassphraseLockscreen.qml qml/Greeter/PinLockscreen.qml → qml/Components/PinLockscreen.qml qml/Dash/ScopeListView.qml+3−2 qml/Greeter/Clock.qml+1−1 qml/Greeter/Greeter.qml+36−3 qml/Greeter/GreeterContent.qml−38 qml/Greeter/GreeterEdgeDemo.qml+102 qml/Greeter/Infographics.qml−2 qml/GreeterShell.qml+283 qml/Hud/Hud.qml+1−4 qml/Notifications/NotificationMenuItemFactory.qml+26−10 qml/Panel/Panel.qml+1−1 qml/Shell.qml+31−177 run.sh+6−4 src/CMakeLists.txt+15−3 src/main.cpp+18−4 tests/autopilot/unity8/application_lifecycle/tests/__init__.py−2 tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+1−29 tests/autopilot/unity8/application_lifecycle/tests/test_greeter.py+75 tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+1 tests/autopilot/unity8/indicators/tests/test_indicators.py−2 tests/autopilot/unity8/process_helpers.py−56 tests/autopilot/unity8/shell/tests/__init__.py+16−4 tests/autopilot/unity8/shell/tests/disabled_test_hud.py+1−7 tests/autopilot/unity8/shell/tests/test_emulators.py−3 tests/autopilot/unity8/shell/tests/test_lock_screen.py+12−13 tests/autopilot/unity8/shell/tests/test_notifications.py+2−14 tests/mocks/AccountsService/AccountsService.cpp+9 tests/mocks/AccountsService/AccountsService.h+7 tests/mocks/CMakeLists.txt+2−1 tests/mocks/LightDM/CMakeLists.txt−50 tests/mocks/SessionManager/CMakeLists.txt+19 tests/mocks/SessionManager/SessionManager.cpp+43 tests/mocks/SessionManager/SessionManager.h+49 tests/mocks/SessionManager/plugin.cpp+34 tests/mocks/SessionManager/plugin.h+34 tests/mocks/SessionManager/qmldir+2 tests/mocks/liblightdm/CMakeLists.txt+4 tests/mocks/LightDM/Greeter.cpp → tests/mocks/liblightdm/Greeter.cpp+11 tests/mocks/LightDM/Greeter.h → tests/mocks/liblightdm/Greeter.h+4 tests/mocks/LightDM/GreeterPrivate.h → tests/mocks/liblightdm/GreeterPrivate.h tests/mocks/LightDM/QLightDM/Greeter → tests/mocks/liblightdm/QLightDM/Greeter tests/mocks/LightDM/QLightDM/InfographicModel → tests/mocks/liblightdm/QLightDM/InfographicModel tests/mocks/LightDM/QLightDM/UsersModel → tests/mocks/liblightdm/QLightDM/UsersModel tests/mocks/LightDM/UsersModel.cpp → tests/mocks/liblightdm/UsersModel.cpp tests/mocks/LightDM/UsersModel.h → tests/mocks/liblightdm/UsersModel.h tests/mocks/LightDM/UsersModelPrivate.h → tests/mocks/liblightdm/UsersModelPrivate.h tests/mocks/LightDM/demo/CMakeLists.txt → tests/mocks/liblightdm/demo/CMakeLists.txt tests/mocks/LightDM/demo/GreeterPrivate.cpp → tests/mocks/liblightdm/demo/GreeterPrivate.cpp tests/mocks/LightDM/demo/UsersModelPrivate.cpp → tests/mocks/liblightdm/demo/UsersModelPrivate.cpp tests/mocks/LightDM/full/CMakeLists.txt → tests/mocks/liblightdm/full/CMakeLists.txt+3−2 tests/mocks/LightDM/full/GreeterPrivate.cpp → tests/mocks/liblightdm/full/GreeterPrivate.cpp tests/mocks/LightDM/full/UsersModelPrivate.cpp → tests/mocks/liblightdm/full/UsersModelPrivate.cpp tests/mocks/LightDM/qmldir → tests/mocks/liblightdm/qmldir tests/mocks/LightDM/single-passphrase/CMakeLists.txt → tests/mocks/liblightdm/single-passphrase/CMakeLists.txt+3−2 tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpp → tests/mocks/liblightdm/single-passphrase/GreeterPrivate.cpp tests/mocks/LightDM/single-passphrase/UsersModelPrivate.cpp → tests/mocks/liblightdm/single-passphrase/UsersModelPrivate.cpp tests/mocks/LightDM/single-pin/CMakeLists.txt → tests/mocks/liblightdm/single-pin/CMakeLists.txt+3−2 tests/mocks/LightDM/single-pin/GreeterPrivate.cpp → tests/mocks/liblightdm/single-pin/GreeterPrivate.cpp tests/mocks/LightDM/single-pin/UsersModelPrivate.cpp → tests/mocks/liblightdm/single-pin/UsersModelPrivate.cpp tests/mocks/LightDM/single/CMakeLists.txt → tests/mocks/liblightdm/single/CMakeLists.txt+3−2 tests/mocks/LightDM/single/GreeterPrivate.cpp → tests/mocks/liblightdm/single/GreeterPrivate.cpp tests/mocks/LightDM/single/UsersModelPrivate.cpp → tests/mocks/liblightdm/single/UsersModelPrivate.cpp tests/plugins/CMakeLists.txt+2−1 tests/plugins/LightDM/CMakeLists.txt+5−4 tests/plugins/SessionManager/CMakeLists.txt+48 tests/plugins/SessionManager/LightDMSessionServer.cpp+38 tests/plugins/SessionManager/LightDMSessionServer.h+40 tests/plugins/SessionManager/LoginManagerServer.cpp+34 tests/plugins/SessionManager/LoginManagerServer.h+37 tests/plugins/SessionManager/LoginSessionServer.cpp+25 tests/plugins/SessionManager/LoginSessionServer.h+39 tests/plugins/SessionManager/client.cpp+88 tests/plugins/SessionManager/interfaces.xml+22 tests/plugins/SessionManager/server.cpp+57 tests/qmltests/CMakeLists.txt+40−49 tests/qmltests/Greeter/tst_Lockscreen.qml+1−2 tests/qmltests/Greeter/tst_Phone.qml+1−17 tests/qmltests/tst_GreeterShell.qml+88 tests/qmltests/tst_Shell.qml+10−64 tools/unlock-device+10−18
CMakeLists.txt+1
@@ -96,6 +96,7 @@ include(autopilot)
9696declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
9797
9898set(SHELL_APP unity8)
99+set(GREETER_APP unity8-greeter)
99100set(SCOPE_TOOL unity-scope-tool)
100101
101102include_directories(
data/51-unity8-greeter.confnew file+2
@@ -0,0 +1,2 @@
1+[SeatDefaults]
2+greeter-session=unity8-greeter
data/CMakeLists.txt+13
@@ -1,7 +1,20 @@
11# generate desktop file
22configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
3+configure_file(${GREETER_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${GREETER_APP}.desktop @ONLY)
34
45# install desktop files
56install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
67 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
78 )
9+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GREETER_APP}.desktop
10+ DESTINATION ${CMAKE_INSTALL_DATADIR}/lightdm/greeters
11+ )
12+install(FILES 51-${GREETER_APP}.conf
13+ DESTINATION ${CMAKE_INSTALL_DATADIR}/lightdm/lightdm.conf.d
14+ )
15+install(FILES ${GREETER_APP}-wrapper
16+ DESTINATION ${CMAKE_INSTALL_BINDIR}
17+ )
18+install(FILES ${GREETER_APP}-init.conf
19+ DESTINATION ${CMAKE_INSTALL_DATADIR}/upstart/sessions
20+ )
data/unity8-greeter-init.confnew file+12
@@ -0,0 +1,12 @@
1+description "Unity 8 Greeter initialization"
2+author "Michael Terry <mterry@ubuntu.com>"
3+
4+start on unity8-greeter-started
5+task
6+emits indicator-services-start
7+
8+script
9+ start --no-wait ofono-setup || true
10+ initctl emit --no-wait indicator-services-start || true
11+ start --no-wait maliit-server || true
12+end script
data/unity8-greeter-wrappernew file+98
@@ -0,0 +1,98 @@
1+#!/bin/sh
2+# -*- Mode: sh; indent-tabs-mode: nil; tab-width: 4 -*-
3+#
4+# Copyright (C) 2011,2013 Canonical Ltd
5+# Author: Michael Terry <michael.terry@canonical.com>
6+#
7+# This program is free software: you can redistribute it and/or modify it under
8+# the terms of the GNU General Public License as published by the Free Software
9+# Foundation, version 3 of the License.
10+#
11+# See http://www.gnu.org/copyleft/gpl.html the full text of the license.
12+
13+# This wrapper merely ensures that init and friends live only as long as this
14+# script does. Otherwise, it's very easy for some processes to not notice that
15+# the session died. We could try to do this in-process, but we want to do this
16+# cleanup even if the greeter aborts.
17+
18+trap cleanup TERM EXIT
19+
20+cleanup()
21+{
22+ trap - TERM EXIT
23+ # Kill upstart and indicators
24+ if [ -n "$INIT_PID" ]; then
25+ kill "$INIT_PID"
26+ fi
27+ if [ -n "$CMD_PID" ]; then
28+ kill "$CMD_PID"
29+ fi
30+ exit 0
31+}
32+
33+set_greeter_var()
34+{
35+ export "$1=$2"
36+ gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "{'$1': '$2'}"
37+ if [ -n "$INIT_PID" ]; then
38+ initctl set-env --global "$1=$2"
39+ fi
40+}
41+
42+SUB_SOCKET=$XDG_RUNTIME_DIR/mir_socket
43+rm -f $SUB_SOCKET # clear socket in case we were hard shut down
44+
45+# If touch session script (which sets up grid units and mir variables) is available, use it
46+TOUCH_WRAPPER=
47+if [ -x /usr/bin/ubuntu-touch-session ]; then
48+ TOUCH_WRAPPER=/usr/bin/ubuntu-touch-session
49+fi
50+
51+# Pretend that we're in an ubuntu-touch session, so that indicator-network
52+# will start.
53+export DESKTOP_SESSION=ubuntu-touch
54+
55+# We disable ofono using pulse. It causes problems with racing with the user's
56+# pulse. We need to come up with a better long-term fix for this, because we
57+# eventually need the greeter to play ringtones for users that aren't logged in.
58+set_greeter_var PA_DISABLED 1
59+
60+# Normal unity8 sessions are entirely driven by Upstart. But greeters
61+# are special. They need access to the file descriptors that lightdm
62+# creates for them and don't want to start all the services that a normal
63+# session would. So it's inconvenient to live within an upstart session.
64+# But... we still want to use Upstart for some services. So launch here.
65+USC_SOCKET=$MIR_SOCKET MIR_SOCKET=$SUB_SOCKET $TOUCH_WRAPPER /sbin/init --user --no-startup-event &
66+INIT_PID=$!
67+while [ ! -e "$XDG_RUNTIME_DIR/upstart/sessions/$INIT_PID.session" ]; do sleep 0.1; done
68+export UPSTART_SESSION=$(/sbin/initctl list-sessions | grep "^$INIT_PID " | cut -d' ' -f2)
69+
70+# Start any pre-greeter tasks if needed (like wizard)
71+/sbin/initctl emit unity8-greeter-starting
72+
73+# Define language here for phone if available. When phone user switches their
74+# language, they expect that to affect the greeter too. But the user doesn't
75+# have permission to switch system language, only their own. So we notice if
76+# the phablet user exists and use their language if so. TODO: talk to design
77+# about whether we should switch language on fly as users are selected (this
78+# is very hard to do technically).
79+#
80+# Do this after unity8-greeter-starting, in case a customization upstart job
81+# changes language.
82+if [ "$(id -u phablet 2>/dev/null)" = "32011" ]; then
83+ USER_LANG=$(gdbus call --system --dest org.freedesktop.Accounts --object-path /org/freedesktop/Accounts/User32011 --method org.freedesktop.DBus.Properties.Get org.freedesktop.Accounts.User Language | cut -d\' -f2)
84+ if [ -n "$USER_LANG" ]; then
85+ set_greeter_var LANGUAGE "$USER_LANG"
86+ fi
87+ USER_LOCALE=$(gdbus call --system --dest org.freedesktop.Accounts --object-path /org/freedesktop/Accounts/User32011 --method org.freedesktop.DBus.Properties.Get org.freedesktop.Accounts.User FormatsLocale | cut -d\' -f2)
88+ if [ -n "$USER_LOCALE" ]; then
89+ set_greeter_var LANG "$USER_LOCALE"
90+ set_greeter_var LC_ALL "$USER_LOCALE"
91+ fi
92+fi
93+
94+# And finally actually start the greeter
95+exec env MIR_SERVER_FILE=$SUB_SOCKET $TOUCH_WRAPPER $@ &
96+CMD_PID=$!
97+wait $CMD_PID
98+CMD_PID=
data/unity8-greeter.desktop.innew file+5
@@ -0,0 +1,5 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Unity 8 Greeter
4+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity8-greeter-wrapper @CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity8-greeter
5+X-LightDM-Session-Type=mir
debian/changelog+6
@@ -1,3 +1,9 @@
1+unity8 (7.87+14.10.20140505-0ubuntu1) UNRELEASED; urgency=medium
2+
3+ * Bump version for Breaks due to unity8-greeter
4+
5+ -- Michael Terry <mterry@ubuntu.com> Wed, 02 Apr 2014 14:39:45 -0400
6+
17unity8 (7.86+14.10.20140527-0ubuntu1) utopic; urgency=low
28
39 [ Andrea Cimitan ]
debian/control+16
@@ -14,6 +14,7 @@ Build-Depends: cmake,
1414 libglib2.0-dev,
1515 libgsettings-qt-dev,
1616 libhud-client2-dev,
17+ liblightdm-qt5-3-dev (>= 1.11.1),
1718 libpulse-dev,
1819 libqmenumodel-dev (>= 0.2.7),
1920 libqt5xmlpatterns5-dev,
@@ -79,6 +80,7 @@ Depends: gsettings-desktop-schemas,
7980 qml-module-qtquick-xmllistmodel,
8081 qtdeclarative5-gsettings1.0,
8182 qtdeclarative5-ubuntu-settings-components,
83+ unity-greeter-session-broadcast,
8284 unity-launcher-impl-3,
8385 unity8-common (= ${source:Version}),
8486 unity8-private (= ${binary:Version}),
@@ -94,6 +96,19 @@ Replaces: ubuntu-touch-session (<< 0.82~),
9496Description: Unity 8 shell
9597 The Unity 8 shell is the primary user interface for Ubuntu devices.
9698
99+Package: unity8-greeter
100+Architecture: any
101+Depends: dbus-x11,
102+ libglib2.0-bin,
103+ lightdm,
104+ unity8 (= ${source:Version}),
105+ ${misc:Depends},
106+ ${shlibs:Depends},
107+Breaks: unity8 (<< 7.87),
108+Replaces: unity8 (<< 7.87),
109+Description: Ubuntu QML greeter
110+ The Ubuntu QML greeter is the primary greeter for Ubuntu devices.
111+
97112Package: unity8-common
98113Architecture: all
99114Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
@@ -132,6 +147,7 @@ Depends: gir1.2-glib-2.0,
132147 ubuntu-ui-toolkit-autopilot,
133148 unity8 (= ${source:Version}),
134149 unity8-fake-env (= ${source:Version}),
150+ unity8-greeter (= ${source:Version}),
135151 url-dispatcher-tools,
136152 ${misc:Depends},
137153 ${python3:Depends},
debian/copyright+1−1
@@ -22,7 +22,7 @@ License: GPL-3
2222 On Debian systems, the full text of the GNU General Public License
2323 version 3 can be found in the file /usr/share/common-licenses/GPL-3.
2424
25−Files: tests/mocks/LightDM/UsersModel.h tests/mocks/LightDM/Greeter.h
25+Files: tests/mocks/liblightdm/UsersModel.h tests/mocks/liblightdm/Greeter.h
2626Copyright: 2013 Canonical Ltd.
2727 2010-2011 David Edmundson
2828 2010-2011 Robert Ancell
debian/rules−4
@@ -34,7 +34,3 @@ override_dh_install:
3434# use private lib directories
3535override_dh_makeshlibs:
3636 dh_makeshlibs -Nunity8-private -Nunity8-fake-env
37−
38−# libMockLightDM-qml.so links against liblightdm-qt5-2.so which doesn't exist
39−override_dh_shlibdeps:
40− dh_shlibdeps -XlibMockLightDM-qml.so
debian/unity8-greeter.installnew file+6
@@ -0,0 +1,6 @@
1+usr/bin/unity8-greeter
2+usr/bin/unity8-greeter-wrapper
3+usr/share/lightdm
4+usr/share/unity8/GreeterShell.qml
5+usr/share/unity8/Greeter
6+usr/share/upstart/sessions/unity8-greeter-*.conf
debian/unity8-private.install+1
@@ -4,6 +4,7 @@ usr/lib/*/unity8/qml/HudClient
44usr/lib/*/unity8/qml/LightDM
55usr/lib/*/unity8/qml/Powerd
66usr/lib/*/unity8/qml/SessionBroadcast
7+usr/lib/*/unity8/qml/SessionManager
78usr/lib/*/unity8/qml/Ubuntu
89usr/lib/*/unity8/qml/Unity
910usr/lib/*/unity8/qml/Utils
debian/unity8.install−1
@@ -1,7 +1,6 @@
11data/unity8.conf usr/share/upstart/sessions/
22usr/bin/unity8
33usr/share/applications/unity8.desktop
4−usr/share/unity8/Greeter
54usr/share/unity8/Hud
65usr/share/unity8/Launcher
76usr/share/unity8/Panel
plugins/AccountsService/AccountsService.cpp+34−11
@@ -24,7 +24,6 @@
2424AccountsService::AccountsService(QObject* parent)
2525 : QObject(parent),
2626 m_service(new AccountsServiceDBusAdaptor(this)),
27− m_user(qgetenv("USER")),
2827 m_demoEdges(false),
2928 m_statsWelcomeScreen(false)
3029{
@@ -32,6 +31,9 @@ AccountsService::AccountsService(QObject* parent)
3231 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
3332 connect(m_service, SIGNAL(maybeChanged(const QString &)),
3433 this, SLOT(maybeChanged(const QString &)));
34+
35+ setUser(qgetenv("USER"));
36+ updateDemoEdgesForCurrentUser();
3537}
3638
3739QString AccountsService::user() const
@@ -57,9 +59,22 @@ bool AccountsService::demoEdges() const
5759void AccountsService::setDemoEdges(bool demoEdges)
5860{
5961 m_demoEdges = demoEdges;
62+ Q_EMIT demoEdgesChanged();
6063 m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
6164}
6265
66+bool AccountsService::demoEdgesForCurrentUser() const
67+{
68+ return m_demoEdgesForCurrentUser;
69+}
70+
71+void AccountsService::setDemoEdgesForCurrentUser(bool demoEdgesForCurrentUser)
72+{
73+ m_demoEdgesForCurrentUser = demoEdgesForCurrentUser;
74+ Q_EMIT demoEdgesForCurrentUserChanged();
75+ m_service->setUserProperty(qgetenv("USER"), "com.canonical.unity.AccountsService", "demo-edges", demoEdgesForCurrentUser);
76+}
77+
6378QString AccountsService::backgroundFile() const
6479{
6580 return m_backgroundFile;
@@ -79,6 +94,15 @@ void AccountsService::updateDemoEdges()
7994 }
8095}
8196
97+void AccountsService::updateDemoEdgesForCurrentUser()
98+{
99+ auto demoEdgesForCurrentUser = m_service->getUserProperty(qgetenv("USER"), "com.canonical.unity.AccountsService", "demo-edges").toBool();
100+ if (m_demoEdgesForCurrentUser != demoEdgesForCurrentUser) {
101+ m_demoEdgesForCurrentUser = demoEdgesForCurrentUser;
102+ Q_EMIT demoEdgesForCurrentUserChanged();
103+ }
104+}
105+
82106void AccountsService::updateBackgroundFile()
83107{
84108 auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
@@ -99,13 +123,14 @@ void AccountsService::updateStatsWelcomeScreen()
99123
100124void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
101125{
102− if (m_user != user) {
103− return;
104− }
105−
106126 if (interface == "com.canonical.unity.AccountsService") {
107127 if (changed.contains("demo-edges")) {
108− updateDemoEdges();
128+ if (qgetenv("USER") == user) {
129+ updateDemoEdgesForCurrentUser();
130+ }
131+ if (m_user == user) {
132+ updateDemoEdges();
133+ }
109134 }
110135 } else if (interface == "com.ubuntu.touch.AccountsService.SecurityPrivacy") {
111136 if (changed.contains("StatsWelcomeScreen")) {
@@ -116,10 +141,8 @@ void AccountsService::propertiesChanged(const QString &user, const QString &inte
116141
117142void AccountsService::maybeChanged(const QString &user)
118143{
119− if (m_user != user) {
120− return;
144+ if (m_user == user) {
145+ // Standard properties might have changed
146+ updateBackgroundFile();
121147 }
122−
123− // Standard properties might have changed
124− updateBackgroundFile();
125148}
plugins/AccountsService/AccountsService.h+9
@@ -35,6 +35,10 @@ class AccountsService: public QObject
3535 READ demoEdges
3636 WRITE setDemoEdges
3737 NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (bool demoEdgesForCurrentUser
39+ READ demoEdgesForCurrentUser
40+ WRITE setDemoEdgesForCurrentUser
41+ NOTIFY demoEdgesForCurrentUserChanged)
3842 Q_PROPERTY (QString backgroundFile
3943 READ backgroundFile
4044 NOTIFY backgroundFileChanged)
@@ -49,12 +53,15 @@ public:
4953 void setUser(const QString &user);
5054 bool demoEdges() const;
5155 void setDemoEdges(bool demoEdges);
56+ bool demoEdgesForCurrentUser() const;
57+ void setDemoEdgesForCurrentUser(bool demoEdgesForCurrentUser);
5258 QString backgroundFile() const;
5359 bool statsWelcomeScreen() const;
5460
5561Q_SIGNALS:
5662 void userChanged();
5763 void demoEdgesChanged();
64+ void demoEdgesForCurrentUserChanged();
5865 void backgroundFileChanged();
5966 void statsWelcomeScreenChanged();
6067
@@ -64,12 +71,14 @@ private Q_SLOTS:
6471
6572private:
6673 void updateDemoEdges();
74+ void updateDemoEdgesForCurrentUser();
6775 void updateBackgroundFile();
6876 void updateStatsWelcomeScreen();
6977
7078 AccountsServiceDBusAdaptor *m_service;
7179 QString m_user;
7280 bool m_demoEdges;
81+ bool m_demoEdgesForCurrentUser;
7382 QString m_backgroundFile;
7483 bool m_statsWelcomeScreen;
7584};
plugins/CMakeLists.txt+1
@@ -17,6 +17,7 @@ add_subdirectory(LightDM)
1717add_subdirectory(Dash)
1818add_subdirectory(Powerd)
1919add_subdirectory(SessionBroadcast)
20+add_subdirectory(SessionManager)
2021add_subdirectory(Ubuntu)
2122add_subdirectory(Unity)
2223add_subdirectory(Utils)
plugins/LightDM/CMakeLists.txt+6−9
@@ -1,23 +1,22 @@
11# Dependencies
22include(FindPkgConfig)
3+pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-3)
34pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
4−# TODO: Once we split out a separate greeter process, uncomment these lines
5−#pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-2)
65
76include_directories(
87 ${CMAKE_CURRENT_SOURCE_DIR}
98 ${CMAKE_CURRENT_BINARY_DIR}
109 ${CMAKE_SOURCE_DIR}/plugins/Utils
11− ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
12− #${LIBLIGHTDM_INCLUDE_DIRS}
10+ ${LIBLIGHTDM_INCLUDE_DIRS}
1311 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
1412)
1513
1614set(QMLPLUGIN_SRC
17− ../Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
15+ ${CMAKE_SOURCE_DIR}/plugins/Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
1816 DBusGreeterList.cpp
1917 Greeter.cpp
2018 plugin.cpp
19+ URLDispatcher.cpp
2120 UsersModel.cpp
2221 )
2322
@@ -26,12 +25,10 @@ add_library(LightDM-qml MODULE
2625 )
2726
2827target_link_libraries(LightDM-qml
29− MockLightDM-demo
30−# TODO: Once we split out a separate greeter process, uncomment these lines
31−# ${LIBLIGHTDM_LDFLAGS}
28+ ${LIBLIGHTDM_LDFLAGS}
3229 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
3330 )
3431
35−qt5_use_modules(LightDM-qml DBus Gui Qml)
32+qt5_use_modules(LightDM-qml DBus Qml)
3633
3734add_unity8_plugin(LightDM 0.1 LightDM TARGETS LightDM-qml)
plugins/LightDM/Greeter.cpp+3
@@ -56,7 +56,10 @@ Greeter::Greeter(QObject* parent)
5656 this, SLOT(showPromptFilter(QString, QLightDM::Greeter::PromptType)));
5757 connect(d->m_greeter, SIGNAL(authenticationComplete()),
5858 this, SLOT(authenticationCompleteFilter()));
59+ connect(d->m_greeter, SIGNAL(idle()), this, SIGNAL(idle()));
60+ connect(d->m_greeter, SIGNAL(reset()), this, SIGNAL(reset()));
5961
62+ d->m_greeter->setResettable(true);
6063 d->m_greeter->connectSync();
6164}
6265
plugins/LightDM/Greeter.h+2
@@ -56,6 +56,8 @@ Q_SIGNALS:
5656 void authenticationComplete();
5757 void authenticationUserChanged(const QString &user);
5858 void promptlessChanged();
59+ void idle();
60+ void reset();
5961
6062 // This signal is emitted by external agents like indicators, and the UI
6163 // should switch to this user if possible.
plugins/LightDM/URLDispatcher.cppnew file+55
@@ -0,0 +1,55 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "URLDispatcher.h"
18+
19+#include <QDBusConnection>
20+
21+class URLDispatcherInterface : public QObject
22+{
23+ Q_OBJECT
24+ Q_CLASSINFO("D-Bus Interface", "com.canonical.URLDispatcher")
25+
26+public:
27+ explicit URLDispatcherInterface(URLDispatcher *parent);
28+
29+ Q_SCRIPTABLE void DispatchURL(const QString &url);
30+};
31+
32+URLDispatcherInterface::URLDispatcherInterface(URLDispatcher *parent)
33+ : QObject(parent)
34+{
35+}
36+
37+void URLDispatcherInterface::DispatchURL(const QString &url)
38+{
39+ Q_EMIT static_cast<URLDispatcher *>(parent())->dispatchURL(url);
40+}
41+
42+URLDispatcher::URLDispatcher(QObject *parent)
43+ : QObject(parent)
44+{
45+ // This class also manages our url-dispatcher interception. We intercept
46+ // url-dispatcher because rather than spawning the handler for the URL in
47+ // our own session, we want to do notify the user session to do it for us
48+ // (and start an unlock in the process).
49+ QDBusConnection connection = QDBusConnection::sessionBus();
50+ URLDispatcherInterface *dispatcher = new URLDispatcherInterface(this);
51+ connection.registerObject("/com/canonical/URLDispatcher", dispatcher, QDBusConnection::ExportScriptableContents);
52+ connection.registerService("com.canonical.URLDispatcher");
53+}
54+
55+#include "URLDispatcher.moc"
plugins/LightDM/URLDispatcher.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef UNITY_URLDISPATCHER_H
18+#define UNITY_URLDISPATCHER_H
19+
20+#include <QObject>
21+#include <QString>
22+
23+class URLDispatcher : public QObject
24+{
25+ Q_OBJECT
26+
27+public:
28+ explicit URLDispatcher(QObject *parent=0);
29+
30+Q_SIGNALS:
31+ void dispatchURL(const QString &url);
32+};
33+
34+#endif
plugins/LightDM/plugin.cpp+9
@@ -20,6 +20,7 @@
2020#include "plugin.h"
2121#include "DBusGreeterList.h"
2222#include "Greeter.h"
23+#include "URLDispatcher.h"
2324#include "UsersModel.h"
2425#include <libusermetricsoutput/ColorTheme.h>
2526#include <libusermetricsoutput/UserMetrics.h>
@@ -46,6 +47,13 @@ static QObject *greeter_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
4647 return greeter;
4748}
4849
50+static QObject *dispatcher_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
51+{
52+ Q_UNUSED(engine)
53+ Q_UNUSED(scriptEngine)
54+ return new URLDispatcher();
55+}
56+
4957static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
5058{
5159 Q_UNUSED(engine)
@@ -67,6 +75,7 @@ void LightDMPlugin::registerTypes(const char *uri)
6775
6876 Q_ASSERT(uri == QLatin1String("LightDM"));
6977 qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider);
78+ qmlRegisterSingletonType<URLDispatcher>(uri, 0, 1, "URLDispatcher", dispatcher_provider);
7079 qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider);
7180 qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable");
7281 qmlRegisterSingletonType<UserMetricsOutput::UserMetrics>(uri, 0, 1, "Infographic", infographic_provider);
plugins/SessionBroadcast/SessionBroadcast.cpp+35
@@ -18,11 +18,26 @@
1818
1919#include "SessionBroadcast.h"
2020#include <QDBusConnection>
21+#include <QDBusConnectionInterface>
22+#include <QDBusInterface>
2123
2224SessionBroadcast::SessionBroadcast(QObject* parent)
2325 : QObject(parent)
2426{
2527 auto connection = QDBusConnection::SM_BUSNAME();
28+ auto interface = connection.interface();
29+ interface->startService("com.canonical.Unity.Greeter.Broadcast");
30+ m_broadcaster = new QDBusInterface("com.canonical.Unity.Greeter.Broadcast",
31+ "/com/canonical/Unity/Greeter/Broadcast",
32+ "com.canonical.Unity.Greeter.Broadcast",
33+ connection, this);
34+
35+ connection.connect("com.canonical.Unity.Greeter.Broadcast",
36+ "/com/canonical/Unity/Greeter/Broadcast",
37+ "com.canonical.Unity.Greeter.Broadcast",
38+ "StartUrl",
39+ this,
40+ SLOT(onStartUrl(const QString &, const QString &)));
2641
2742 connection.connect("com.canonical.Unity.Greeter.Broadcast",
2843 "/com/canonical/Unity/Greeter/Broadcast",
@@ -32,6 +47,26 @@ SessionBroadcast::SessionBroadcast(QObject* parent)
3247 SLOT(onShowHome(const QString &)));
3348}
3449
50+void SessionBroadcast::requestUrlStart(const QString &username, const QString &url)
51+{
52+ m_broadcaster->asyncCall("RequestUrlStart", username, url);
53+}
54+
55+void SessionBroadcast::requestHomeShown(const QString &username)
56+{
57+ m_broadcaster->asyncCall("RequestHomeShown", username);
58+}
59+
60+void SessionBroadcast::onStartUrl(const QString &username, const QString &url)
61+{
62+ // Since this signal is just used for testing, we don't *really* care if
63+ // username matches, but just in case we do eventually use the signal, we
64+ // should only listen to our own requests.
65+ if (username == qgetenv("USER")) {
66+ Q_EMIT startUrl(url);
67+ }
68+}
69+
3570void SessionBroadcast::onShowHome(const QString &username)
3671{
3772 // Only listen to requests meant for us
plugins/SessionBroadcast/SessionBroadcast.h+11
@@ -31,11 +31,22 @@ class SessionBroadcast: public QObject
3131public:
3232 explicit SessionBroadcast(QObject *parent = 0);
3333
34+ Q_INVOKABLE void requestUrlStart(const QString &username, const QString &url);
35+ Q_INVOKABLE void requestHomeShown(const QString &username);
36+
3437Q_SIGNALS:
38+ // This signal isn't actually used by the shell
39+ // (unity-greeter-session-broadcast handles launching an app for us), but
40+ // it's useful for testing the plugin.
41+ void startUrl(const QString &url);
3542 void showHome();
3643
3744private Q_SLOTS:
45+ void onStartUrl(const QString &username, const QString &url);
3846 void onShowHome(const QString &username);
47+
48+private:
49+ QDBusInterface *m_broadcaster;
3950};
4051
4152#endif
plugins/SessionManager/CMakeLists.txtnew file+22
@@ -0,0 +1,22 @@
1+set(QMLPLUGIN_SRC
2+ plugin.cpp
3+ SessionManager.cpp
4+ )
5+
6+include_directories(
7+ ${Qt5DBus_INCLUDE_DIRS}
8+ )
9+
10+add_definitions(-DSM_BUSNAME=systemBus)
11+
12+add_library(SessionManager-qml MODULE
13+ ${QMLPLUGIN_SRC}
14+ )
15+
16+target_link_libraries(SessionManager-qml
17+ ${Qt5DBus_LIBRARIES}
18+ )
19+
20+qt5_use_modules(SessionManager-qml Qml)
21+
22+add_unity8_plugin(SessionManager 0.1 SessionManager TARGETS SessionManager-qml)
plugins/SessionManager/SessionManager.cppnew file+124
@@ -0,0 +1,124 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "SessionManager.h"
20+#include <QtCore/QEvent>
21+#include <QtDBus/QDBusPendingReply>
22+
23+SessionManager::SessionManager(QObject* parent)
24+ : QObject(parent),
25+ l1_manager(NULL),
26+ l1_session(NULL),
27+ ldm_session(NULL),
28+ is_active(true) // assume we're active w/o logind
29+{
30+ l1_manager = new QDBusInterface("org.freedesktop.login1",
31+ "/org/freedesktop/login1",
32+ "org.freedesktop.login1.Manager",
33+ QDBusConnection::SM_BUSNAME(), this);
34+ if (l1_manager->isValid() && QString(qgetenv("XDG_SESSION_ID")) != "") {
35+ QDBusPendingCall pcall = l1_manager->asyncCall("GetSession", QString(qgetenv("XDG_SESSION_ID")));
36+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
37+ QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
38+ this, SLOT(getSessionSlot(QDBusPendingCallWatcher*)));
39+ }
40+
41+ if (QString(qgetenv("XDG_SESSION_PATH")) != "") {
42+ ldm_session = new QDBusInterface("org.freedesktop.DisplayManager",
43+ QString(qgetenv("XDG_SESSION_PATH")),
44+ "org.freedesktop.DisplayManager.Session",
45+ QDBusConnection::SM_BUSNAME(), this);
46+ }
47+}
48+
49+bool SessionManager::active() const
50+{
51+ // We cache this value for performance reasons, as QDBusInterface does not
52+ // cache for us.
53+ return is_active;
54+}
55+
56+void SessionManager::lock()
57+{
58+ // We use ldm_session to handle locking rather than l1_session, because
59+ // l1_session doesn't have permissions to lock from the user session, but
60+ // ldm_session does. This is what the rest of Ubuntu uses to lock.
61+ if (ldm_session != NULL && ldm_session->isValid())
62+ ldm_session->asyncCall("Lock");
63+}
64+
65+void SessionManager::getSessionSlot(QDBusPendingCallWatcher *watcher)
66+{
67+ QDBusPendingReply<QDBusObjectPath> reply = *watcher;
68+ if (!reply.isError()) {
69+ QDBusObjectPath path = reply.argumentAt<0>();
70+ l1_session = new QDBusInterface("org.freedesktop.login1",
71+ path.path(),
72+ "org.freedesktop.login1.Session",
73+ l1_manager->connection(), this);
74+
75+ l1_manager->connection().connect("org.freedesktop.login1",
76+ path.path(),
77+ "org.freedesktop.DBus.Properties",
78+ "PropertiesChanged",
79+ this,
80+ SLOT(propertiesChanged(QString, QVariantMap, QStringList)));
81+
82+ // Login1 is very odd about emitting PropertiesChanged. It often does
83+ // not do so when active is becoming false. But it always does when
84+ // it becomes true. So we watch for the "Lock" signal too, which is a
85+ // reliably hint that active is false.
86+ l1_manager->connection().connect("org.freedesktop.login1",
87+ path.path(),
88+ "org.freedesktop.login1.Session",
89+ "Lock",
90+ this,
91+ SLOT(sessionLocked()));
92+
93+ propertiesChanged("", QVariantMap(), QStringList() << "Active");
94+ }
95+ watcher->deleteLater();
96+}
97+
98+void SessionManager::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
99+{
100+ Q_UNUSED(interface)
101+
102+ QVariant value = changed.value("Active");
103+
104+ // If Active isn't in changed, check if we were at least notified about it
105+ // changing on the server. Also check if IdleHint was modified, because
106+ // sometimes logind does not emit a changed signal for Active becoming
107+ // false, but will emit for IdleHint when that does happen.
108+ if (!value.isValid() && (invalid.contains("Active") || invalid.contains("IdleHint") || changed.contains("IdleHint")) && l1_session->isValid()) {
109+ value = l1_session->property("Active");
110+ if (!value.isValid())
111+ value = QVariant(false);
112+ }
113+
114+ if (value.isValid() && value.toBool() != is_active) {
115+ is_active = value.toBool();
116+ Q_EMIT activeChanged();
117+ }
118+}
119+
120+void SessionManager::sessionLocked()
121+{
122+ is_active = false;
123+ Q_EMIT activeChanged();
124+}
plugins/SessionManager/SessionManager.hnew file+61
@@ -0,0 +1,61 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_SESSIONMANAGER_H
21+#define UNITY_SESSIONMANAGER_H
22+
23+#include <QtCore/QObject>
24+#include <QtCore/QString>
25+#include <QtCore/QStringList>
26+#include <QtCore/QVariantMap>
27+#include <QtDBus/QDBusInterface>
28+#include <QtDBus/QDBusPendingCallWatcher>
29+
30+class SessionManager: public QObject
31+{
32+ Q_OBJECT
33+ Q_PROPERTY(bool active
34+ READ active
35+ NOTIFY activeChanged
36+ FINAL)
37+
38+public:
39+ explicit SessionManager(QObject *parent = 0);
40+
41+ bool active() const;
42+
43+public Q_SLOTS:
44+ void lock();
45+
46+Q_SIGNALS:
47+ void activeChanged();
48+
49+private Q_SLOTS:
50+ void getSessionSlot(QDBusPendingCallWatcher *watcher);
51+ void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
52+ void sessionLocked();
53+
54+private:
55+ QDBusInterface *l1_manager;
56+ QDBusInterface *l1_session;
57+ QDBusInterface *ldm_session;
58+ bool is_active;
59+};
60+
61+#endif
plugins/SessionManager/plugin.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "plugin.h"
21+#include "SessionManager.h"
22+#include <QtQml/qqml.h>
23+
24+static QObject *sessionmanager_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25+{
26+ Q_UNUSED(engine)
27+ Q_UNUSED(scriptEngine)
28+ return new SessionManager();
29+}
30+
31+void SessionManagerPlugin::registerTypes(const char *uri)
32+{
33+ Q_ASSERT(uri == QLatin1String("SessionManager"));
34+ qmlRegisterSingletonType<SessionManager>(uri, 0, 1, "SessionManager", sessionmanager_provider);
35+}
plugins/SessionManager/plugin.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef SESSIONMANAGER_PLUGIN_H
21+#define SESSIONMANAGER_PLUGIN_H
22+
23+#include <QtQml/QQmlEngine>
24+#include <QtQml/QQmlExtensionPlugin>
25+
26+class SessionManagerPlugin : public QQmlExtensionPlugin
27+{
28+ Q_OBJECT
29+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30+
31+public:
32+ void registerTypes(const char *uri);
33+};
34+
35+#endif
plugins/SessionManager/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module SessionManager
2+plugin SessionManager-qml
plugins/Unity/Launcher/backend/launcherbackend.cpp+16−2
@@ -37,12 +37,15 @@ public:
3737 bool countVisible;
3838};
3939
40−LauncherBackend::LauncherBackend(QObject *parent):
40+LauncherBackend::LauncherBackend(bool greeterMode, QObject *parent):
4141 QDBusVirtualObject(parent),
42+ m_greeterMode(greeterMode),
4243 m_accounts(nullptr)
4344{
4445#ifndef LAUNCHER_TESTING
4546 m_accounts = new AccountsServiceDBusAdaptor(this);
47+ connect(m_accounts, SIGNAL(propertiesChanged(QString, QString, QStringList)),
48+ this, SLOT(accountsListChanged(QString, QString, QStringList)));
4649#endif
4750 m_user = qgetenv("USER");
4851 syncFromAccounts();
@@ -225,7 +228,7 @@ void LauncherBackend::setCountVisible(const QString &appId, bool visible) const
225228
226229void LauncherBackend::setUser(const QString &username)
227230{
228− if (qgetenv("USER") == "lightdm" && m_user != username) {
231+ if (m_greeterMode && m_user != username) {
229232 m_user = username;
230233 syncFromAccounts();
231234 }
@@ -238,6 +241,15 @@ void LauncherBackend::triggerQuickListAction(const QString &appId, const QString
238241 Q_UNUSED(quickListId)
239242}
240243
244+void LauncherBackend::accountsListChanged(const QString &user, const QString &interface, const QStringList &changed)
245+{
246+ if (m_greeterMode && user == m_user &&
247+ interface == "com.canonical.unity.AccountsService" &&
248+ changed.contains("launcher-items")) {
249+ syncFromAccounts();
250+ }
251+}
252+
241253void LauncherBackend::syncFromAccounts()
242254{
243255 QList<QVariantMap> apps;
@@ -299,6 +311,8 @@ void LauncherBackend::syncFromAccounts()
299311 loadFromVariant(app.toMap());
300312 }
301313 }
314+
315+ Q_EMIT refreshApplications();
302316}
303317
304318void LauncherBackend::syncToAccounts()
plugins/Unity/Launcher/backend/launcherbackend.h+7−1
@@ -42,7 +42,7 @@ class LauncherBackend : public QDBusVirtualObject
4242 friend LauncherBackendTest;
4343
4444public:
45− LauncherBackend(QObject *parent = 0);
45+ LauncherBackend(bool greeterMode = false, QObject *parent = 0);
4646 virtual ~LauncherBackend();
4747
4848 /**
@@ -162,6 +162,7 @@ public:
162162 virtual QString introspect (const QString &path) const;
163163
164164Q_SIGNALS:
165+ void refreshApplications() const;
165166 void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList) const;
166167 void progressChanged(const QString &appId, int progress) const;
167168 void countChanged(const QString &appId, int count) const;
@@ -178,6 +179,8 @@ private:
178179 void syncFromAccounts();
179180 void syncToAccounts();
180181
182+ bool m_greeterMode;
183+
181184 QList<QString> m_storedApps;
182185 mutable QHash<QString, LauncherBackendItem*> m_itemCache;
183186
@@ -186,6 +189,9 @@ private:
186189
187190 void emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const;
188191
192+private Q_SLOTS:
193+ void accountsListChanged(const QString &user, const QString &interface, const QStringList &changed);
194+
189195protected: /* Protected to allow testing */
190196 LauncherBackendItem* getItem(const QString& appId) const;
191197
plugins/Unity/Launcher/launcheritem.cpp+14−9
@@ -22,12 +22,13 @@
2222
2323#include <libintl.h>
2424
25−LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
25+LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, bool pinnable, QObject *parent) :
2626 LauncherItemInterface(parent),
2727 m_appId(appId),
2828 m_name(name),
2929 m_icon(icon),
3030 m_pinned(false),
31+ m_pinnable(pinnable),
3132 m_running(false),
3233 m_recent(false),
3334 m_progress(-1),
@@ -38,10 +39,12 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
3839 QuickListEntry nameAction;
3940 nameAction.setText(m_name);
4041 m_quickList->appendAction(nameAction);
41− QuickListEntry pinningAction;
42− pinningAction.setActionId("pin_item");
43− pinningAction.setText(gettext("Lock to Launcher"));
44− m_quickList->appendAction(pinningAction);
42+ if (m_pinnable) {
43+ QuickListEntry pinningAction;
44+ pinningAction.setActionId("pin_item");
45+ pinningAction.setText(gettext("Lock to Launcher"));
46+ m_quickList->appendAction(pinningAction);
47+ }
4548}
4649
4750QString LauncherItem::appId() const
@@ -68,10 +71,12 @@ void LauncherItem::setPinned(bool pinned)
6871{
6972 if (m_pinned != pinned) {
7073 m_pinned = pinned;
71− QuickListEntry entry;
72− entry.setActionId("pin_item");
73− entry.setText(pinned ? gettext("Unlock from Launcher") : gettext("Lock to Launcher"));
74− m_quickList->updateAction(entry);
74+ if (m_pinnable) {
75+ QuickListEntry entry;
76+ entry.setActionId("pin_item");
77+ entry.setText(pinned ? gettext("Unlock from Launcher") : gettext("Lock to Launcher"));
78+ m_quickList->updateAction(entry);
79+ }
7580 Q_EMIT pinnedChanged(pinned);
7681 }
7782}
plugins/Unity/Launcher/launcheritem.h+2−1
@@ -32,7 +32,7 @@ class LauncherItem: public LauncherItemInterface
3232{
3333 Q_OBJECT
3434public:
35− LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0);
35+ LauncherItem(const QString &appId, const QString &name, const QString &icon, bool pinnable, QObject *parent = 0);
3636
3737 QString appId() const;
3838 QString name() const;
@@ -67,6 +67,7 @@ private:
6767 QString m_name;
6868 QString m_icon;
6969 bool m_pinned;
70+ bool m_pinnable;
7071 bool m_running;
7172 bool m_recent;
7273 int m_progress;
plugins/Unity/Launcher/launchermodel.cpp+41−11
@@ -27,20 +27,15 @@ using namespace unity::shell::application;
2727
2828LauncherModel::LauncherModel(QObject *parent):
2929 LauncherModelInterface(parent),
30− m_backend(new LauncherBackend(this)),
30+ m_greeterMode(qgetenv("XDG_SESSION_CLASS") == "greeter"),
31+ m_backend(new LauncherBackend(m_greeterMode, this)),
3132 m_appManager(0)
3233{
3334 connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
3435 connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
36+ connect(m_backend, SIGNAL(refreshApplications()), SLOT(refreshStoredApplications()));
3537
36− Q_FOREACH (const QString &entry, m_backend->storedApplications()) {
37− LauncherItem *item = new LauncherItem(entry,
38− m_backend->displayName(entry),
39− m_backend->icon(entry),
40− this);
41− item->setPinned(true);
42− m_list.append(item);
43− }
38+ refreshStoredApplications();
4439}
4540
4641LauncherModel::~LauncherModel()
@@ -139,7 +134,8 @@ void LauncherModel::pin(const QString &appId, int index)
139134 beginInsertRows(QModelIndex(), index, index);
140135 LauncherItem *item = new LauncherItem(appId,
141136 m_backend->displayName(appId),
142− m_backend->icon(appId));
137+ m_backend->icon(appId),
138+ !m_greeterMode);
143139 item->setPinned(true);
144140 m_list.insert(index, item);
145141 endInsertRows();
@@ -199,6 +195,40 @@ void LauncherModel::setUser(const QString &username)
199195 m_backend->setUser(username);
200196}
201197
198+void LauncherModel::refreshStoredApplications()
199+{
200+ // First remove any existing ones
201+ QList<int> storedAppIndices;
202+ for (int i = 0; i < m_list.count(); ++i) {
203+ if (!m_list.at(i)->recent()) {
204+ storedAppIndices << i;
205+ }
206+ }
207+ int run = 0;
208+ while (storedAppIndices.count() > 0) {
209+ beginRemoveRows(QModelIndex(), storedAppIndices.first() - run, storedAppIndices.first() - run);
210+ m_list.takeAt(storedAppIndices.first() - run)->deleteLater();
211+ endRemoveRows();
212+ storedAppIndices.takeFirst();
213+ ++run;
214+ }
215+
216+ // Now insert all stored apps at beginning of list
217+ QStringList storedApplications = m_backend->storedApplications();
218+ beginInsertRows(QModelIndex(), 0, storedApplications.size() - 1);
219+ run = 0;
220+ Q_FOREACH (const QString &entry, storedApplications) {
221+ LauncherItem *item = new LauncherItem(entry,
222+ m_backend->displayName(entry),
223+ m_backend->icon(entry),
224+ !m_greeterMode,
225+ this);
226+ item->setPinned(true);
227+ m_list.insert(run++, item);
228+ }
229+ endInsertRows();
230+}
231+
202232ApplicationManagerInterface *LauncherModel::applicationManager() const
203233{
204234 return m_appManager;
@@ -302,7 +332,7 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
302332 if (found) {
303333 // Shall we paint some running/recent app highlight? If yes, do it here.
304334 } else {
305− LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString());
335+ LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), !m_greeterMode);
306336 item->setRecent(true);
307337 item->setFocused(app->focused());
308338
plugins/Unity/Launcher/launchermodel.h+2
@@ -62,6 +62,7 @@ private:
6262private Q_SLOTS:
6363 void progressChanged(const QString &appId, int progress);
6464 void countChanged(const QString &appId, int count);
65+ void refreshStoredApplications();
6566
6667 void applicationAdded(const QModelIndex &parent, int row);
6768 void applicationRemoved(const QModelIndex &parent, int row);
@@ -69,6 +70,7 @@ private Q_SLOTS:
6970
7071private:
7172 QList<LauncherItem*> m_list;
73+ bool m_greeterMode;
7274 LauncherBackend *m_backend;
7375 ApplicationManagerInterface *m_appManager;
7476};
po/ug.po+2−1
@@ -6,11 +6,12 @@
66msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
9−"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9+"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2014-04-10 11:13-0400\n"
1111"PO-Revision-Date: 2014-04-22 05:46+0000\n"
1212"Last-Translator: abdurahman <Unknown>\n"
1313"Language-Team: Uyghur <ug@li.org>\n"
14+"Language: \n"
1415"MIME-Version: 1.0\n"
1516"Content-Type: text/plain; charset=UTF-8\n"
1617"Content-Transfer-Encoding: 8bit\n"
qml/Components/BasicShell.qmlnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Unity.Application 0.1
20+import "../Components"
21+
22+FocusScope {
23+ id: shell
24+
25+ // this is only here to select the width / height of the window if not running fullscreen
26+ property bool tablet: false
27+ width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
28+ height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
29+
30+ property real edgeSize: units.gu(2)
31+
32+ property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "../graphics/tablet_background.jpg" : "../graphics/phone_background.jpg")
33+ property url background
34+ property url backgroundSource
35+ property url backgroundFallbackSource
36+ property url backgroundFinal: (backgroundSource != undefined && backgroundSource != "") ? backgroundSource : (backgroundFallbackSource != undefined && backgroundFallbackSource != "") ? backgroundFallbackSource : shell.defaultBackground
37+ onBackgroundFinalChanged: shell.background = backgroundFinal
38+
39+ // This is a dummy image that is needed to determine if the picture url
40+ // in backgroundSettings points to a valid picture file.
41+ // We can't do this with the real background image because setting a
42+ // new source in onStatusChanged triggers a binding loop detection
43+ // inside Image, which causes it not to render even though a valid source
44+ // would be set. We don't mind about this image staying black and just
45+ // use it for verification to populate the source for the real
46+ // background image.
47+ Image {
48+ source: shell.background
49+ height: 0
50+ width: 0
51+ sourceSize.height: 0
52+ sourceSize.width: 0
53+ onStatusChanged: {
54+ if (status == Image.Error) {
55+ if (source != shell.defaultBackground) {
56+ shell.background = defaultBackground
57+ } else {
58+ // In case even our default background fails to load...
59+ shell.background = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='#000'/></svg>"
60+ }
61+ }
62+ }
63+ }
64+
65+ VolumeControl {
66+ id: volumeControl
67+ }
68+
69+ Keys.onVolumeUpPressed: volumeControl.volumeUp()
70+ Keys.onVolumeDownPressed: volumeControl.volumeDown()
71+
72+ function hideIndicatorMenu(delay) {
73+ panel.hideIndicatorMenu(delay);
74+ }
75+
76+ focus: true
77+ onFocusChanged: if (!focus) forceActiveFocus();
78+
79+ Binding {
80+ target: i18n
81+ property: "domain"
82+ value: "unity8"
83+ }
84+}
qml/Components/EdgeDemo.qml+1−53
@@ -15,13 +15,11 @@
1515 */
1616
1717import AccountsService 0.1
18−import LightDM 0.1 as LightDM
1918import QtQuick 2.0
2019
2120Item {
2221 id: demo
2322
24− property Item greeter
2523 property Item dash
2624 property Item launcher
2725 property Item indicators
@@ -36,7 +34,6 @@ Item {
3634 property bool paused: false
3735
3836 onPausedChanged: {
39− if (d.rightEdgeDemo) d.rightEdgeDemo.paused = paused
4037 if (d.topEdgeDemo) d.topEdgeDemo.paused = paused
4138 if (d.bottomEdgeDemo) d.bottomEdgeDemo.paused = paused
4239 if (d.leftEdgeDemo) d.leftEdgeDemo.paused = paused
@@ -45,16 +42,6 @@ Item {
4542
4643 function hideEdgeDemoInShell() {
4744 AccountsService.demoEdges = false;
48− stopDemo();
49− }
50−
51− function hideEdgeDemoInGreeter() {
52− // TODO: AccountsService.demoEdges = false as lightdm user
53− }
54−
55− function hideEdgeDemos() {
56− hideEdgeDemoInGreeter();
57− hideEdgeDemoInShell();
5845 }
5946
6047 function stopDemo() {
@@ -62,7 +49,6 @@ Item {
6249 dashEnabled = true
6350 panelEnabled = true
6451 panelContentEnabled = true
65− if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
6652 if (d.topEdgeDemo) d.topEdgeDemo.destroy()
6753 if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy()
6854 if (d.leftEdgeDemo) d.leftEdgeDemo.destroy()
@@ -79,24 +65,17 @@ Item {
7965 panelEnabled = false;
8066 panelContentEnabled = false;
8167
82− // Begin with either greeter or dash, depending on which is visible
83− if (greeter && greeter.shown) {
84− startRightEdgeDemo()
85− } else {
86− startTopEdgeDemo()
87− }
68+ startTopEdgeDemo()
8869 }
8970
9071 QtObject {
9172 id: d
9273 property Component overlay
93− property QtObject rightEdgeDemo
9474 property QtObject topEdgeDemo
9575 property QtObject bottomEdgeDemo
9676 property QtObject leftEdgeDemo
9777 property QtObject finalEdgeDemo
9878 property bool showEdgeDemo: AccountsService.demoEdges
99− property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user
10079
10180 onShowEdgeDemoChanged: {
10281 stopDemo()
@@ -106,37 +85,6 @@ Item {
10685 }
10786 }
10887
109− function startRightEdgeDemo() {
110− if (demo.greeter) {
111− d.rightEdgeDemo = d.overlay.createObject(demo.greeter, {
112− "edge": "right",
113− "title": i18n.tr("Right edge"),
114− "text": i18n.tr("Try swiping from the right edge to unlock the phone"),
115− "anchors.fill": demo.greeter,
116− });
117− }
118− if (d.rightEdgeDemo) {
119− d.rightEdgeDemo.onSkip.connect(demo.hideEdgeDemos)
120− } else {
121− stopDemo();
122− }
123− }
124−
125− Connections {
126− target: demo.greeter
127−
128− function hide() {
129− if (d.rightEdgeDemo && d.rightEdgeDemo.available) {
130− d.rightEdgeDemo.hide()
131− hideEdgeDemoInGreeter()
132− startTopEdgeDemo()
133− }
134− }
135−
136− onUnlocked: hide()
137− onShownChanged: if (!greeter.shown) hide()
138− }
139−
14088 function startTopEdgeDemo() {
14189 demo.panelEnabled = true;
14290 if (demo.dash && demo.underlay) {
qml/Greeter/Lockscreen.qml → qml/Components/Lockscreen.qmlrenamed−20
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 1.0
1919import Ubuntu.Components.Popups 1.0
20−import "../Components"
2120
2221Showable {
2322 id: root
@@ -49,8 +48,6 @@ Showable {
4948 property int minPinLength: -1
5049 property int maxPinLength: -1
5150
52− property url background: ""
53−
5451 signal entered(string passphrase)
5552 signal cancel()
5653 signal emergencyCall()
@@ -76,23 +73,6 @@ Showable {
7673 PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
7774 }
7875
79− Rectangle {
80− // In case background fails to load or is undefined
81− id: backgroundBackup
82− anchors.fill: parent
83− color: "black"
84− }
85−
86− Image {
87− id: backgroundImage
88− objectName: "lockscreenBackground"
89− anchors {
90− fill: parent
91− }
92− source: root.required ? root.background : ""
93− fillMode: Image.PreserveAspectCrop
94− }
95−
9676 MouseArea {
9777 anchors.fill: root
9878 }
qml/Components/PageHeader.qml+3−2
@@ -18,6 +18,7 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Ubuntu.Components.Popups 0.1
2020import Ubuntu.Components.ListItems 0.1 as ListItem
21+import SessionManager 0.1
2122import Unity 0.2
2223
2324Item {
@@ -51,8 +52,8 @@ Item {
5152 }
5253
5354 Connections {
54− target: greeter
55− onShownChanged: if (shown) resetSearch()
55+ target: SessionManager
56+ onActiveChanged: if (!SessionManager.active) resetSearch()
5657 }
5758
5859 Flickable {
qml/Greeter/PassphraseLockscreen.qml → qml/Components/PassphraseLockscreen.qmlrenamed

The content is the same.

qml/Greeter/PinLockscreen.qml → qml/Components/PinLockscreen.qmlrenamed

The content is the same.

qml/Dash/ScopeListView.qml+3−2
@@ -16,13 +16,14 @@
1616
1717import QtQuick 2.0
1818import Dash 0.1
19+import SessionManager 0.1
1920
2021ListViewWithPageHeader {
2122 maximumFlickVelocity: height * 10
2223 flickDeceleration: height * 2
2324
2425 Connections {
25− target: greeter
26− onShownChanged: if (greeter.shown) showHeader()
26+ target: SessionManager
27+ onActiveChanged: if (!SessionManager.active) showHeader()
2728 }
2829}
qml/Greeter/Clock.qml+1−1
@@ -39,7 +39,7 @@ Item {
3939
4040 busName: "com.canonical.indicator.datetime"
4141 actionsObjectPath: "/com/canonical/indicator/datetime"
42− menuObjectPath: clock.visible ? "/com/canonical/indicator/datetime/phone" : ""
42+ menuObjectPath: clock.visible ? "/com/canonical/indicator/datetime/phone_greeter" : ""
4343
4444 Indicators.RootActionState {
4545 menu: timeModel.model
qml/Greeter/Greeter.qml+36−3
@@ -23,9 +23,9 @@ import "../Components"
2323Showable {
2424 id: greeter
2525 enabled: shown
26− created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
26+ created: greeterContentLoader.status == Loader.Ready
2727
28− property url defaultBackground
28+ property url background
2929
3030 // 1 when fully shown and 0 when fully hidden
3131 property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
@@ -118,6 +118,36 @@ Showable {
118118 }
119119 }
120120
121+ Rectangle {
122+ // To hide lockscreen until background finished fading in
123+ id: backgroundBackup
124+ anchors {
125+ fill: parent
126+ topMargin: -greeter.y
127+ }
128+ color: "black"
129+ }
130+
131+ CrossFadeImage {
132+ id: backgroundImage
133+ objectName: "greeterBackground"
134+ anchors {
135+ fill: parent
136+ topMargin: -greeter.y
137+ }
138+ source: greeter.background
139+ fillMode: Image.PreserveAspectCrop
140+
141+ StandardAnimation {
142+ running: true
143+ target: backgroundImage
144+ property: "opacity"
145+ from: 0.0
146+ to: 1.0
147+ duration: 800
148+ }
149+ }
150+
121151 Loader {
122152 id: greeterContentLoader
123153 objectName: "greeterContentLoader"
@@ -125,7 +155,6 @@ Showable {
125155 property var model: LightDM.Users
126156 property int currentIndex: 0
127157 property var infographicModel: LightDM.Infographic
128− readonly property int backgroundTopMargin: -greeter.y
129158
130159 source: required ? "GreeterContent.qml" : ""
131160
@@ -145,6 +174,10 @@ Showable {
145174 }
146175
147176 onTease: showLabelAnimation.start()
177+ onShownChanged: {
178+ showLabelAnimation.stop()
179+ swipeHint.opacity = 0
180+ }
148181
149182 Label {
150183 id: swipeHint
qml/Greeter/GreeterContent.qml−38
@@ -24,46 +24,9 @@ Item {
2424 id: root
2525 anchors.fill: parent
2626
27− property bool ready: background.source == "" || background.status == Image.Ready || background.status == Image.Error
28−
2927 signal selected(int uid)
3028 signal unlocked(int uid)
3129
32− Rectangle {
33− // In case background fails to load
34− id: backgroundBackup
35− anchors.fill: parent
36− color: "black"
37− }
38−
39− property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : greeter.defaultBackground
40− onBackgroundValueChanged: background.source = backgroundValue
41−
42− CrossFadeImage {
43− id: background
44− objectName: "greeterBackground"
45− anchors {
46− fill: parent
47− topMargin: backgroundTopMargin
48− }
49− fillMode: Image.PreserveAspectCrop
50− }
51−
52− // See Shell.qml's backgroundSettings treatment for why we need a separate
53− // Image, but it boils down to avoiding binding loop detection.
54− Image {
55− source: background.source
56− height: 0
57− width: 0
58− sourceSize.height: 0
59− sourceSize.width: 0
60− onStatusChanged: {
61− if (status == Image.Error && source != greeter.defaultBackground) {
62− background.source = greeter.defaultBackground
63− }
64− }
65− }
66−
6730 Rectangle {
6831 anchors.fill: parent
6932 color: "black"
@@ -145,7 +108,6 @@ Item {
145108
146109 Clock {
147110 id: clock
148− visible: narrowMode
149111
150112 anchors {
151113 top: parent.top
qml/Greeter/GreeterEdgeDemo.qmlnew file+102
@@ -0,0 +1,102 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import AccountsService 0.1
18+import LightDM 0.1 as LightDM
19+import QtQuick 2.0
20+
21+Item {
22+ id: demo
23+
24+ property Item greeter
25+
26+ property bool active: false
27+ property bool paused: false
28+
29+ onPausedChanged: {
30+ if (d.rightEdgeDemo) d.rightEdgeDemo.paused = paused
31+ }
32+
33+ function hideEdgeDemoInShell() {
34+ AccountsService.demoEdges = false;
35+ }
36+
37+ function hideEdgeDemoInGreeter() {
38+ AccountsService.demoEdgesForCurrentUser = false;
39+ }
40+
41+ function hideEdgeDemos() {
42+ hideEdgeDemoInGreeter();
43+ hideEdgeDemoInShell();
44+ }
45+
46+ function startDemo() {
47+ if (!d.overlay) {
48+ d.overlay = Qt.createComponent("../Components/EdgeDemoOverlay.qml")
49+ }
50+ startRightEdgeDemo()
51+ }
52+
53+ function stopDemo() {
54+ active = false
55+ if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
56+ }
57+
58+ QtObject {
59+ id: d
60+ property Component overlay
61+ property QtObject rightEdgeDemo
62+ property bool showEdgeDemoInGreeter: AccountsService.demoEdgesForCurrentUser && AccountsService.demoEdges
63+
64+ onShowEdgeDemoInGreeterChanged: {
65+ stopDemo()
66+ if (d.showEdgeDemoInGreeter) {
67+ startDemo()
68+ }
69+ }
70+ }
71+
72+ function startRightEdgeDemo() {
73+ active = true;
74+ if (demo.greeter) {
75+ d.rightEdgeDemo = d.overlay.createObject(demo.greeter, {
76+ "edge": "right",
77+ "title": i18n.tr("Right edge"),
78+ "text": i18n.tr("Try swiping from the right edge to unlock the phone"),
79+ "anchors.fill": demo.greeter,
80+ });
81+ }
82+ if (d.rightEdgeDemo) {
83+ d.rightEdgeDemo.onSkip.connect(demo.hideEdgeDemos)
84+ } else {
85+ stopDemo();
86+ }
87+ }
88+
89+ Connections {
90+ target: demo.greeter
91+
92+ function hide() {
93+ if (d.rightEdgeDemo && d.rightEdgeDemo.available) {
94+ d.rightEdgeDemo.hide()
95+ hideEdgeDemoInGreeter()
96+ }
97+ }
98+
99+ onUnlocked: hide()
100+ onShownChanged: if (!greeter.shown) hide()
101+ }
102+}
qml/Greeter/Infographics.qml−2
@@ -59,8 +59,6 @@ Item {
5959
6060 visible: model.label !== ""
6161
62− Component.onCompleted: startShowAnimation()
63−
6462 Item {
6563 id: dataCircle
6664 objectName: "dataCircle"
qml/GreeterShell.qmlnew file+283
@@ -0,0 +1,283 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import AccountsService 0.1
18+import GSettings 1.0
19+import LightDM 0.1 as LightDM
20+import Powerd 0.1
21+import QtQuick 2.0
22+import SessionBroadcast 0.1
23+import Ubuntu.Components 0.1
24+import Unity.Application 0.1
25+import Unity.Launcher 0.1
26+import "Components"
27+import "Greeter"
28+import "Launcher"
29+import "Panel"
30+import "Notifications"
31+import Unity.Notifications 1.0 as NotificationBackend
32+
33+BasicShell {
34+ id: shell
35+
36+ function activateApplication(appId) {
37+ SessionBroadcast.requestUrlStart(LightDM.Greeter.authenticationUser, appId)
38+ greeter.hide()
39+ }
40+
41+ GSettings {
42+ id: backgroundSettings
43+ schema.id: "org.gnome.desktop.background"
44+ }
45+ backgroundFallbackSource: backgroundSettings.pictureUri // for ease of customization by system builders
46+ backgroundSource: AccountsService.backgroundFile
47+
48+ Lockscreen {
49+ id: lockscreen
50+ objectName: "lockscreen"
51+
52+ hides: [launcher, panel.indicators]
53+ shown: false
54+ enabled: true
55+ showAnimation: StandardAnimation { property: "opacity"; to: 1 }
56+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
57+ y: panel.panelHeight
58+ x: required ? 0 : - width
59+ width: parent.width
60+ height: parent.height - panel.panelHeight
61+ minPinLength: 4
62+ maxPinLength: 4
63+
64+ onEntered: LightDM.Greeter.respond(passphrase);
65+ onCancel: greeter.show()
66+
67+ Component.onCompleted: {
68+ if (LightDM.Users.count == 1) {
69+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
70+ }
71+ }
72+ }
73+
74+ Connections {
75+ target: LightDM.Greeter
76+
77+ onIdle: {
78+ greeter.showNow()
79+ }
80+
81+ onShowPrompt: {
82+ if (LightDM.Users.count == 1) {
83+ // TODO: There's no better way for now to determine if its a PIN or a passphrase.
84+ if (text == "PIN") {
85+ lockscreen.alphaNumeric = false
86+ } else {
87+ lockscreen.alphaNumeric = true
88+ }
89+ lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
90+ lockscreen.show();
91+ }
92+ }
93+
94+ onAuthenticationComplete: {
95+ if (LightDM.Greeter.promptless) {
96+ return;
97+ }
98+ if (LightDM.Greeter.authenticated) {
99+ lockscreen.hide();
100+ } else {
101+ lockscreen.clear(true);
102+ }
103+ }
104+ }
105+
106+ Rectangle {
107+ anchors.fill: parent
108+ color: "black"
109+ opacity: greeterWrapper.showProgress * 0.8
110+ }
111+
112+ Item {
113+ // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
114+ id: greeterWrapper
115+ x: launcher.progress
116+ width: parent.width
117+ height: parent.height
118+
119+ Behavior on x {
120+ enabled: !launcher.dashSwipe
121+ StandardAnimation {}
122+ }
123+
124+ readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
125+ onShowProgressChanged: if (LightDM.Greeter.promptless && showProgress === 0) greeter.login()
126+
127+ Greeter {
128+ id: greeter
129+ objectName: "greeter"
130+
131+ available: true
132+ hides: [launcher, panel.indicators]
133+ shown: true
134+ background: shell.background
135+
136+ y: panel.panelHeight
137+ width: parent.width
138+ height: parent.height - panel.panelHeight
139+
140+ dragHandleWidth: shell.edgeSize
141+
142+ function login() {
143+ enabled = false;
144+ LightDM.Greeter.startSessionSync();
145+ enabled = true;
146+ }
147+
148+ onShownChanged: {
149+ if (shown) {
150+ lockscreen.reset();
151+ // If there is only one user, we start authenticating with that one here.
152+ // If there are more users, the Greeter will handle that
153+ if (LightDM.Users.count == 1) {
154+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
155+ }
156+ greeter.forceActiveFocus();
157+ }
158+ }
159+
160+ onUnlocked: hide()
161+ onSelected: {
162+ // Update launcher items for new user
163+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
164+ AccountsService.user = user;
165+ LauncherModel.setUser(user);
166+ }
167+ onTease: launcher.tease()
168+ }
169+ }
170+
171+ InputFilterArea {
172+ anchors.fill: parent
173+ blockInput: true
174+ }
175+
176+ Item {
177+ id: overlay
178+
179+ anchors.fill: parent
180+
181+ Panel {
182+ id: panel
183+ anchors.fill: parent //because this draws indicator menus
184+ indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
185+ indicators {
186+ hides: [launcher]
187+ available: !edgeDemo.active
188+ }
189+ fullscreenMode: false
190+ searchVisible: false
191+ }
192+
193+ Launcher {
194+ id: launcher
195+
196+ readonly property bool dashSwipe: progress > 0
197+
198+ anchors.top: parent.top
199+ anchors.bottom: parent.bottom
200+ width: parent.width
201+ dragAreaWidth: shell.edgeSize
202+ available: !edgeDemo.active
203+ onLauncherApplicationSelected: {
204+ shell.activateApplication("application:///" + appId + ".desktop")
205+ }
206+ onShownChanged: {
207+ if (shown) {
208+ panel.indicators.hide()
209+ }
210+ }
211+ onDash: {
212+ greeter.hideRight()
213+ hide()
214+ }
215+ onShowDashHome: {
216+ SessionBroadcast.requestHomeShown(LightDM.Greeter.authenticationUser)
217+ greeter.hide()
218+ }
219+ }
220+
221+ Notifications {
222+ id: notifications
223+
224+ model: NotificationBackend.Model
225+ margin: units.gu(1)
226+
227+ anchors {
228+ top: parent.top
229+ right: parent.right
230+ bottom: parent.bottom
231+ topMargin: panel.panelHeight
232+ }
233+ states: [
234+ State {
235+ name: "narrow"
236+ when: overlay.width <= units.gu(60)
237+ AnchorChanges { target: notifications; anchors.left: parent.left }
238+ },
239+ State {
240+ name: "wide"
241+ when: overlay.width > units.gu(60)
242+ AnchorChanges { target: notifications; anchors.left: undefined }
243+ PropertyChanges { target: notifications; width: units.gu(38) }
244+ }
245+ ]
246+
247+ InputFilterArea {
248+ anchors { left: parent.left; right: parent.right }
249+ height: parent.contentHeight
250+ blockInput: height > 0
251+ }
252+ }
253+ }
254+
255+ OSKController {
256+ anchors.topMargin: panel.panelHeight
257+ anchors.fill: parent // as needs to know the geometry of the shell
258+ }
259+
260+ Connections {
261+ id: powerConnection
262+ target: Powerd
263+
264+ onDisplayPowerStateChange: {
265+ if (status == Powerd.Off) {
266+ greeter.show();
267+ edgeDemo.paused = true;
268+ } else if (status == Powerd.On) {
269+ edgeDemo.paused = false;
270+ }
271+ }
272+ }
273+
274+ Connections {
275+ target: LightDM.URLDispatcher
276+ onDispatchURL: shell.activateApplication(url)
277+ }
278+
279+ GreeterEdgeDemo {
280+ id: edgeDemo
281+ greeter: greeter
282+ }
283+}
qml/Hud/Hud.qml+1−4
@@ -227,10 +227,7 @@ Item {
227227 width: parent.width
228228
229229 onYChanged: {
230− if (greeter.shown) {
231− showAnimation.duration = 0
232− hideAnimation.duration = 0
233− } else if (!showAnimation.running && !hideAnimation.running) {
230+ if (!showAnimation.running && !hideAnimation.running) {
234231 if (parent.height > 0) {
235232 showAnimation.duration = Math.min(showableAnimationDuration * (1 - (parent.height - y) / parent.height), showableAnimationDuration)
236233 hideAnimation.duration = showableAnimationDuration - showAnimation.duration
qml/Notifications/NotificationMenuItemFactory.qml+26−10
@@ -20,7 +20,6 @@
2020import QtQuick 2.0
2121import Ubuntu.Components 0.1
2222import "../Components"
23−import "../Greeter"
2423
2524Loader {
2625 id: menuFactory
@@ -98,19 +97,36 @@ Loader {
9897 Component {
9998 id: pinLock
10099
101− Lockscreen {
102− anchors.left: parent.left; anchors.right: parent.right
100+ Item {
103101 height: menuFactory.maxHeight
104− placeholderText: i18n.tr("Please enter SIM PIN")
105− background: shell.background
102+ anchors.left: parent.left
103+ anchors.right: parent.right
104+
105+ Rectangle {
106+ // In case background fails to load or is undefined
107+ anchors.fill: parent
108+ color: "black"
109+ }
106110
107− onEntered: {
108− menuModel.changeState(menuIndex, passphrase);
109− entryEnabled = false;
111+ Image {
112+ objectName: "lockscreenBackground"
113+ anchors.fill: parent
114+ source: shell.background
115+ fillMode: Image.PreserveAspectCrop
110116 }
111117
112− onCancel: {
113− menuModel.activate(menuIndex, false);
118+ Lockscreen {
119+ anchors.fill: parent
120+ placeholderText: i18n.tr("Please enter SIM PIN")
121+
122+ onEntered: {
123+ menuModel.changeState(menuIndex, passphrase);
124+ entryEnabled = false;
125+ }
126+
127+ onCancel: {
128+ menuModel.activate(menuIndex, false);
129+ }
114130 }
115131 }
116132 }
qml/Panel/Panel.qml+1−1
@@ -62,7 +62,7 @@ Item {
6262 height: __panelMinusSeparatorLineHeight
6363 y: 0
6464
65− Behavior on y { StandardAnimation { duration: UbuntuAnimation.FastDuration } }
65+ Behavior on y { StandardAnimation { duration: 500 } }
6666 }
6767
6868 PanelSeparatorLine {
qml/Shell.qml+31−177
@@ -21,28 +21,19 @@ import Unity.Application 0.1
2121import Ubuntu.Components 0.1
2222import Ubuntu.Gestures 0.1
2323import Unity.Launcher 0.1
24−import LightDM 0.1 as LightDM
2524import Powerd 0.1
2625import SessionBroadcast 0.1
26+import SessionManager 0.1
2727import "Dash"
28−import "Greeter"
2928import "Launcher"
3029import "Panel"
3130import "Components"
3231import "Notifications"
3332import Unity.Notifications 1.0 as NotificationBackend
3433
35−FocusScope {
34+BasicShell {
3635 id: shell
3736
38− // this is only here to select the width / height of the window if not running fullscreen
39− property bool tablet: false
40− width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
41− height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
42−
43− property real edgeSize: units.gu(2)
44− property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
45− property url background
4637 readonly property real panelHeight: panel.panelHeight
4738
4839 property bool dashShown: dash.shown
@@ -78,17 +69,7 @@ FocusScope {
7869 id: backgroundSettings
7970 schema.id: "org.gnome.desktop.background"
8071 }
81− property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
82− onGSettingsPictureChanged: {
83− shell.background = gSettingsPicture
84− }
85−
86− VolumeControl {
87− id: volumeControl
88− }
89−
90− Keys.onVolumeUpPressed: volumeControl.volumeUp()
91− Keys.onVolumeDownPressed: volumeControl.volumeDown()
72+ backgroundSource: backgroundSettings.pictureUri
9273
9374 Item {
9475 id: underlayClipper
@@ -135,10 +116,9 @@ FocusScope {
135116 id: dash
136117 objectName: "dash"
137118
138− available: !greeter.shown && !lockscreen.shown
139119 hides: [stages, launcher, panel.indicators]
140− shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
141− enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
120+ shown: disappearingAnimationProgress !== 1.0
121+ enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
142122
143123 anchors {
144124 fill: parent
@@ -226,7 +206,6 @@ FocusScope {
226206 shown = true;
227207 panel.indicators.hide();
228208 edgeDemo.stopDemo();
229− greeter.hide();
230209 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
231210 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
232211 }
@@ -267,6 +246,12 @@ FocusScope {
267246 }
268247 }
269248
249+ Binding {
250+ target: ApplicationManager
251+ property: "suspended"
252+ value: !SessionManager.active
253+ }
254+
270255 Loader {
271256 id: applicationsDisplayLoader
272257 anchors.fill: parent
@@ -291,132 +276,9 @@ FocusScope {
291276 }
292277 }
293278
294− Lockscreen {
295− id: lockscreen
296− objectName: "lockscreen"
297−
298− readonly property int backgroundTopMargin: -panel.panelHeight
299−
300− hides: [launcher, panel.indicators]
301− shown: false
302− enabled: true
303− showAnimation: StandardAnimation { property: "opacity"; to: 1 }
304− hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
305− y: panel.panelHeight
306− x: required ? 0 : - width
307− width: parent.width
308− height: parent.height - panel.panelHeight
309− background: shell.background
310− minPinLength: 4
311− maxPinLength: 4
312−
313− onEntered: LightDM.Greeter.respond(passphrase);
314− onCancel: greeter.show()
315−
316− Component.onCompleted: {
317− if (LightDM.Users.count == 1) {
318− LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
319− }
320− }
321− }
322−
323− Connections {
324− target: LightDM.Greeter
325−
326− onShowPrompt: {
327− if (LightDM.Users.count == 1) {
328− // TODO: There's no better way for now to determine if its a PIN or a passphrase.
329− if (text == "PIN") {
330− lockscreen.alphaNumeric = false
331− } else {
332− lockscreen.alphaNumeric = true
333− }
334− lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
335− lockscreen.show();
336− }
337− }
338−
339− onAuthenticationComplete: {
340− if (LightDM.Greeter.promptless) {
341− return;
342− }
343− if (LightDM.Greeter.authenticated) {
344− lockscreen.hide();
345− } else {
346− lockscreen.clear(true);
347− }
348− }
349− }
350−
351− Rectangle {
352− anchors.fill: parent
353− color: "black"
354− opacity: greeterWrapper.showProgress * 0.8
355− }
356−
357− Item {
358− // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
359− id: greeterWrapper
360− x: launcher.progress
361− y: panel.panelHeight
362− width: parent.width
363− height: parent.height - panel.panelHeight
364−
365− Behavior on x {
366− enabled: !launcher.dashSwipe
367− StandardAnimation {}
368− }
369−
370− readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
371−
372− Greeter {
373− id: greeter
374− objectName: "greeter"
375−
376− available: true
377− hides: [launcher, panel.indicators]
378− shown: true
379−
380− defaultBackground: shell.background
381−
382− width: parent.width
383− height: parent.height
384−
385− dragHandleWidth: shell.edgeSize
386−
387− onShownChanged: {
388− if (shown) {
389− lockscreen.reset();
390− // If there is only one user, we start authenticating with that one here.
391− // If there are more users, the Greeter will handle that
392− if (LightDM.Users.count == 1) {
393− LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
394− }
395− greeter.forceActiveFocus();
396− }
397− }
398−
399− onUnlocked: greeter.hide()
400− onSelected: {
401− // Update launcher items for new user
402− var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
403− AccountsService.user = user;
404− LauncherModel.setUser(user);
405− }
406−
407− onTease: launcher.tease()
408−
409− Binding {
410− target: ApplicationManager
411− property: "suspended"
412− value: greeter.shown && greeterWrapper.showProgress == 1
413− }
414− }
415− }
416−
417279 InputFilterArea {
418280 anchors.fill: parent
419− blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
281+ blockInput: ApplicationManager.focusedApplicationId.length === 0 || launcher.shown
420282 || panel.indicators.shown
421283 }
422284
@@ -428,7 +290,7 @@ FocusScope {
428290 // We ignore any display-off signals when the proximity sensor
429291 // is active. This usually indicates something like a phone call.
430292 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
431− greeter.showNow();
293+ SessionManager.lock();
432294 }
433295
434296 // No reason to chew demo CPU when user isn't watching
@@ -440,17 +302,12 @@ FocusScope {
440302 }
441303 }
442304
443− function showHome() {
444− var animate = !greeter.shown && !stages.shown
445− greeter.hide()
305+ function showHome(fromLauncher) {
306+ var animate = fromLauncher && !stages.shown
446307 dash.setCurrentScope("clickscope", animate, false)
447308 stages.hide()
448309 }
449310
450− function hideIndicatorMenu(delay) {
451− panel.hideIndicatorMenu(delay);
452− }
453−
454311 Item {
455312 id: overlay
456313
@@ -467,8 +324,8 @@ FocusScope {
467324 }
468325 property string focusedAppId: ApplicationManager.focusedApplicationId
469326 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
470− fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown
471− searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
327+ fullscreenMode: focusedApplication && stages.fullscreen
328+ searchVisible: dash.shown && dash.searchable
472329
473330 InputFilterArea {
474331 anchors {
@@ -506,8 +363,9 @@ FocusScope {
506363 if (edgeDemo.running)
507364 return;
508365
509− showHome()
366+ showHome(true)
510367 }
368+
511369 onDash: {
512370 if (stages.shown && !stages.overlayMode) {
513371 if (!stages.locked) {
@@ -515,10 +373,6 @@ FocusScope {
515373 launcher.hide();
516374 }
517375 }
518− if (greeter.shown) {
519− greeter.hideRight();
520− launcher.hide();
521− }
522376 }
523377 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
524378 onLauncherApplicationSelected: {
@@ -535,7 +389,7 @@ FocusScope {
535389 Rectangle {
536390 id: modalNotificationBackground
537391
538− visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
392+ visible: notifications.useModal && (notifications.state == "narrow")
539393 color: "#000000"
540394 anchors.fill: parent
541395 opacity: 0.5
@@ -582,10 +436,17 @@ FocusScope {
582436 blockInput: height > 0
583437 }
584438 }
585− }
586439
587− focus: true
588− onFocusChanged: if (!focus) forceActiveFocus();
440+ Connections {
441+ target: SessionManager
442+ onActiveChanged: {
443+ if (!SessionManager.active) {
444+ launcher.hide()
445+ panel.indicators.hide()
446+ }
447+ }
448+ }
449+ }
589450
590451 InputFilterArea {
591452 anchors {
@@ -607,12 +468,6 @@ FocusScope {
607468 blockInput: true
608469 }
609470
610− Binding {
611− target: i18n
612− property: "domain"
613− value: "unity8"
614− }
615−
616471 OSKController {
617472 anchors.topMargin: panel.panelHeight
618473 anchors.fill: parent // as needs to know the geometry of the shell
@@ -644,7 +499,6 @@ FocusScope {
644499
645500 EdgeDemo {
646501 id: edgeDemo
647− greeter: greeter
648502 launcher: launcher
649503 dash: dash
650504 indicators: panel.indicators
@@ -653,6 +507,6 @@ FocusScope {
653507
654508 Connections {
655509 target: SessionBroadcast
656− onShowHome: showHome()
510+ onShowHome: showHome(false)
657511 }
658512}
run.sh+6−4
@@ -18,13 +18,14 @@ usage() {
1818 echo " -p, --pinlock Use a pin protected user." >&2
1919 echo " -k, --keylock Use a passphrase protected user." >&2
2020 echo " -g, --gdb Run through gdb." >&2
21+ echo " -G, --greeter Run the greeter instead of the shell." >&2
2122 echo " -h, --help Show this help." >&2
2223 echo " -m, --nomousetouch Run without -mousetouch argument." >&2
2324 echo >&2
2425 exit 1
2526}
2627
27−ARGS=`getopt -n$0 -u -a --longoptions="fake,pinlock,keylock,gdb,help,nomousetouch" -o "fpkghm" -- "$@"`
28+ARGS=`getopt -n$0 -u -a --longoptions="fake,pinlock,keylock,gdb,greeter,help,nomousetouch" -o "fpkgGhm" -- "$@"`
2829[ $? -ne 0 ] && usage
2930eval set -- "$ARGS"
3031
@@ -35,6 +36,7 @@ do
3536 -p|--pinlock) PINLOCK=true;;
3637 -k|--keylock) KEYLOCK=true;;
3738 -g|--gdb) GDB=true;;
39+ -G|--greeter) QML_PHONE_SHELL_PATH=./builddir/src/unity8-greeter;;
3840 -h|--help) usage;;
3941 -m|--nomousetouch) MOUSE_TOUCH=false;;
4042 --) shift;break;;
@@ -44,17 +46,17 @@ done
4446
4547if $FAKE; then
4648 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
47− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single
49+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single
4850fi
4951
5052if $PINLOCK; then
5153 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
52− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-pin
54+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single-pin
5355fi
5456
5557if $KEYLOCK; then
5658 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
57− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-passphrase
59+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single-passphrase
5860fi
5961
6062# Force icon theme if running on the desktop, otherwise gnome theme (if running
src/CMakeLists.txt+15−3
@@ -15,24 +15,36 @@ file(GLOB_RECURSE QML_FILES
1515 ${CMAKE_SOURCE_DIR}/tests/*.svg
1616)
1717
18−add_executable(${SHELL_APP}
18+set(COMMON_SRCS
1919 ApplicationArguments.h
2020 main.cpp
2121 MouseTouchAdaptor.cpp
2222 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
23−)
23+ )
24+add_executable(${SHELL_APP} ${COMMON_SRCS})
25+add_executable(${GREETER_APP} ${COMMON_SRCS})
26+
27+set_target_properties(${SHELL_APP} PROPERTIES
28+ COMPILE_DEFINITIONS "UNITY8_GREETER=0"
29+ )
30+set_target_properties(${GREETER_APP} PROPERTIES
31+ COMPILE_DEFINITIONS "UNITY8_GREETER=1"
32+ )
2433
2534qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
35+qt5_use_modules(${GREETER_APP} Gui Qml Quick Test)
2636pkg_check_modules(XCB REQUIRED xcb)
2737
2838if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
2939 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
40+ set_target_properties(${GREETER_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
3041
3142 target_link_libraries(${SHELL_APP} ${XCB_LDFLAGS})
43+ target_link_libraries(${GREETER_APP} ${XCB_LDFLAGS})
3244endif()
3345
3446# install binaries
35−install(TARGETS ${SHELL_APP}
47+install(TARGETS ${SHELL_APP} ${GREETER_APP}
3648 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
3749 )
3850
src/main.cpp+18−4
@@ -26,6 +26,7 @@
2626#include <qpa/qplatformnativeinterface.h>
2727#include <QLibrary>
2828#include <QDebug>
29+#include <QProcess>
2930#include <libintl.h>
3031#include <dlfcn.h>
3132#include <csignal>
@@ -42,7 +43,7 @@ int startShell(int argc, const char** argv, void* server)
4243{
4344 const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
4445
45− QGuiApplication::setApplicationName("Unity 8");
46+ QGuiApplication::setApplicationName(UNITY8_GREETER ? "Unity 8 Greeter" : "Unity 8");
4647 QGuiApplication *application;
4748
4849 QCommandLineParser parser;
@@ -93,7 +94,7 @@ Load the testability driver");
9394
9495 QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
9596 if (indicatorProfile.isEmpty()) {
96− indicatorProfile = "phone";
97+ indicatorProfile = UNITY8_GREETER ? "phone_greeter" : "phone";
9798 }
9899
99100 resolveIconTheme();
@@ -152,7 +153,7 @@ Load the testability driver");
152153 nativeInterface->setProperty("ubuntuSessionType", 1);
153154 view->setProperty("role", 2); // INDICATOR_ACTOR_ROLE
154155
155− QUrl source(::qmlDirectory()+"Shell.qml");
156+ QUrl source(::qmlDirectory() + (UNITY8_GREETER ? "GreeterShell.qml" : "Shell.qml"));
156157 prependImportPaths(view->engine(), ::overrideImportPaths());
157158 if (!isUbuntuMirServer) {
158159 prependImportPaths(view->engine(), ::nonMirImportPaths());
@@ -160,7 +161,7 @@ Load the testability driver");
160161 appendImportPaths(view->engine(), ::fallbackImportPaths());
161162
162163 view->setSource(source);
163− view->setColor("transparent");
164+ view->setColor(Qt::transparent);
164165
165166 if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || parser.isSet(fullscreenOption)) {
166167 view->showFullScreen();
@@ -168,6 +169,19 @@ Load the testability driver");
168169 view->show();
169170 }
170171
172+#if UNITY8_GREETER
173+ if (isUbuntuMirServer) {
174+ // Add alpha to surface, so that the greeter can bleed through
175+ QSurfaceFormat format;
176+ format.setAlphaBufferSize(8);
177+ view->setFormat(format);
178+ }
179+
180+ if (!QProcess::startDetached("/sbin/initctl emit --no-wait unity8-greeter-started")) {
181+ qDebug() << "Unable to send unity8-greeter-started event to Upstart";
182+ }
183+#endif
184+
171185 int result = application->exec();
172186
173187 delete view;
tests/autopilot/unity8/application_lifecycle/tests/__init__.py−2
@@ -31,8 +31,6 @@ class ApplicationLifeCycleTestCase(tests.UnityTestCase):
3131 super(ApplicationLifeCycleTestCase, self).setUp()
3232 self._qml_mock_enabled = False
3333 self._data_dirs_mock_enabled = False
34− unity_proxy = self.launch_unity()
35− process_helpers.unlock_unity(unity_proxy)
3634
3735 def create_test_application(self):
3836 desktop_file_dict = fixture_setup.DEFAULT_DESKTOP_FILE_DICT
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+1−29
@@ -24,11 +24,8 @@ from __future__ import absolute_import
2424import logging
2525import os
2626
27−from autopilot.matchers import Eventually
2827from autopilot.platform import model
29−from testtools.matchers import Equals
3028
31−from unity8 import process_helpers
3229from unity8.application_lifecycle import tests
3330
3431
@@ -41,6 +38,7 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
4138 if model() == 'Desktop':
4239 self.skipTest('Test cannot be run on the desktop.')
4340 super(ApplicationLifecycleTests, self).setUp()
41+ self.launch_unity()
4442
4543 def swipe_screen_from_right(self):
4644 width = self.main_window.width
@@ -89,29 +87,3 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
8987 self.swipe_screen_from_right()
9088
9189 self.assert_current_focused_application(application1_name)
92−
93− def test_greeter_hides_on_app_open(self):
94− """Greeter should hide when an app is opened"""
95− process_helpers.lock_unity()
96− greeter = self.main_window.get_greeter()
97− self.assertThat(greeter.created, Eventually(Equals(True)))
98−
99− application_name = self.launch_fake_app()
100− self.assertThat(greeter.created, Eventually(Equals(False)))
101− self.assert_current_focused_application(application_name)
102−
103− def test_greeter_hides_on_app_focus(self):
104− """Greeter should hide when an app is re-focused"""
105− application_name = self.launch_fake_app()
106− self.assert_current_focused_application(application_name)
107−
108− self.main_window.show_dash_swiping()
109− self.assert_current_focused_application('')
110−
111− process_helpers.lock_unity()
112− greeter = self.main_window.get_greeter()
113− self.assertThat(greeter.created, Eventually(Equals(True)))
114−
115− self.launch_upstart_application(application_name)
116− self.assertThat(greeter.created, Eventually(Equals(False)))
117− self.assert_current_focused_application(application_name)
tests/autopilot/unity8/application_lifecycle/tests/test_greeter.pynew file+75
@@ -0,0 +1,75 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013, 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle in the greeter."""
21+
22+from __future__ import absolute_import
23+
24+import logging
25+import os
26+import subprocess
27+
28+from autopilot.matchers import Eventually
29+from autopilot.platform import model
30+from testtools.matchers import Equals
31+
32+from unity8.application_lifecycle import tests
33+from unity8.shell import with_lightdm_mock
34+
35+
36+logger = logging.getLogger(__name__)
37+
38+
39+class GreeterApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
40+
41+ def setUp(self):
42+ if model() == 'Desktop':
43+ self.skipTest('Test cannot be run on the desktop.')
44+ super(GreeterApplicationLifecycleTests, self).setUp()
45+ # Kill user's url-dispatcher daemon, because we want to own its dbus
46+ # name during these tests.
47+ try:
48+ subprocess.check_output(
49+ ["/sbin/initctl", "stop", "url-dispatcher"],
50+ stderr=subprocess.STDOUT
51+ )
52+ except subprocess.CalledProcessError:
53+ logger.warning("Appears url-dispatcher was already stopped!")
54+ self.addCleanup(self._start_dispatcher)
55+ self.launch_greeter()
56+
57+ def _start_dispatcher(self):
58+ subprocess.call(
59+ ["/sbin/initctl", "start", "url-dispatcher"],
60+ stderr=subprocess.STDOUT
61+ )
62+
63+ @with_lightdm_mock("single")
64+ def test_greeter_hides_on_url_dispatcher(self):
65+ """Greeter should hide when an app is opened"""
66+ greeter = self.main_window.get_greeter()
67+ self.assertThat(greeter.created, Eventually(Equals(True)))
68+
69+ _, desktop_file_path = self.create_test_application()
70+ desktop_file_name = os.path.basename(desktop_file_path)
71+ application_name, _ = os.path.splitext(desktop_file_name)
72+
73+ subprocess.check_call(
74+ ['url-dispatcher', 'application:///{}'.format(desktop_file_name)])
75+ self.assertThat(greeter.created, Eventually(Equals(False)))
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+1
@@ -33,6 +33,7 @@ class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
3333 if platform.model() == 'Desktop':
3434 self.skipTest("URL dispatcher doesn't work on the desktop.")
3535 super(URLDispatcherTestCase, self).setUp()
36+ self.launch_unity()
3637
3738 def test_swipe_out_application_started_by_url_dispatcher(self):
3839 _, desktop_file_path = self.create_test_application()
tests/autopilot/unity8/indicators/tests/test_indicators.py−2
@@ -22,7 +22,6 @@ from testscenarios import multiply_scenarios
2222
2323from autopilot import platform
2424
25−from unity8.process_helpers import unlock_unity
2625from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
2726
2827
@@ -35,7 +34,6 @@ class IndicatorTestCase(UnityTestCase):
3534 self.skipTest('Test cannot be run on the desktop.')
3635 super(IndicatorTestCase, self).setUp()
3736 self.unity_proxy = self.launch_unity()
38− unlock_unity(self.unity_proxy)
3937
4038
4139class IndicatorExistsTestCase(IndicatorTestCase):
tests/autopilot/unity8/process_helpers.py−56
@@ -40,62 +40,6 @@ class CannotAccessUnity(Exception):
4040 pass
4141
4242
43−def unlock_unity(unity_proxy_obj=None):
44− """Helper function that attempts to unlock the unity greeter.
45−
46− If unity_proxy_object is None create a proxy object by querying for the
47− running unity process.
48− Otherwise re-use the passed proxy object.
49−
50− :raises RuntimeError: if the greeter attempts and fails to be unlocked.
51−
52− :raises RuntimeWarning: when the greeter cannot be found because it is
53− already unlocked.
54− :raises CannotAccessUnity: if unity is not introspectable or cannot be
55− found on dbus.
56− :raises CannotAccessUnity: if unity's upstart status is not "start" or the
57− upstart job cannot be found at all.
58−
59− """
60− if unity_proxy_obj is None:
61− try:
62− pid = _get_unity_pid()
63− unity = _get_unity_proxy_object(pid)
64− main_window = unity.select_single(main_window_emulator.QQuickView)
65− except ProcessSearchError as e:
66− raise CannotAccessUnity(
67− "Cannot introspect unity, make sure that it has been started "
68− "with testability. Perhaps use the function "
69− "'restart_unity_with_testability' this module provides."
70− "(%s)"
71− % str(e)
72− )
73− else:
74− main_window = unity_proxy_obj.select_single(
75− main_window_emulator.QQuickView)
76−
77− greeter = main_window.get_greeter()
78− if greeter.created == False:
79− raise RuntimeWarning("Greeter appears to be already unlocked.")
80−
81− # Because of potential input jerkiness under heavy load,
82− # retry unlocking the greeter two times.
83− # https://bugs.launchpad.net/ubuntu/+bug/1260113
84−
85− retries = 3
86− while retries > 0:
87− try:
88− greeter.swipe()
89− except AssertionError:
90− retries -= 1
91− if retries == 0:
92− raise
93− logger.info("Failed to unlock greeter, trying again...")
94− else:
95− logger.info("Greeter unlocked, continuing.")
96− break
97−
98−
9943def lock_unity(unity_proxy_obj=None):
10044 """Helper function that attempts to lock the unity greeter."""
10145 import evdev, time
tests/autopilot/unity8/shell/tests/__init__.py+16−4
@@ -249,9 +249,9 @@ class UnityTestCase(AutopilotTestCase):
249249 "%s=%s" % (key, value)
250250 ], stderr=subprocess.STDOUT)
251251
252− def launch_unity(self, **kwargs):
252+ def _launch(self, executable, ready_func, **kwargs):
253253 """Launch the unity shell, return a proxy object for it."""
254− binary_path = get_binary_path()
254+ binary_path = get_binary_path(executable)
255255 lib_path = get_lib_path()
256256
257257 logger.info(
@@ -293,11 +293,19 @@ class UnityTestCase(AutopilotTestCase):
293293
294294 # Ensure that the dash is visible before we return:
295295 logger.debug("Unity started, waiting for it to be ready.")
296− self.assertUnityReady()
296+ ready_func()
297297 logger.debug("Unity loaded and ready.")
298298
299299 return app_proxy
300300
301+ def launch_unity(self, **kwargs):
302+ """Launch the unity shell, return a proxy object for it."""
303+ return self._launch("unity8", self.assertUnityReady, **kwargs)
304+
305+ def launch_greeter(self, **kwargs):
306+ """Launch the unity shell, return a proxy object for it."""
307+ return self._launch("unity8-greeter", self.assertGreeterReady, **kwargs)
308+
301309 def _launch_unity_with_upstart(self, binary_path, args):
302310 logger.info("Starting unity")
303311 self._patch_environment("QT_LOAD_TESTABILITY", 1)
@@ -344,7 +352,7 @@ class UnityTestCase(AutopilotTestCase):
344352 def _get_lightdm_mock_path(self, mock_type):
345353 lib_path = get_mocks_library_path()
346354 lightdm_mock_path = os.path.abspath(
347− os.path.join(lib_path, "LightDM", mock_type)
355+ os.path.join(lib_path, "liblightdm", mock_type)
348356 )
349357
350358 if not os.path.exists(lightdm_mock_path):
@@ -386,6 +394,10 @@ class UnityTestCase(AutopilotTestCase):
386394 )
387395 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
388396
397+ def assertGreeterReady(self):
398+ greeter = self.main_window.get_greeter()
399+ self.assertThat(greeter.created, Eventually(Equals(True)))
400+
389401 def get_dash(self):
390402 dash = self._proxy.wait_select_single(Dash)
391403 return dash
tests/autopilot/unity8/shell/tests/disabled_test_hud.py+1−7
@@ -19,8 +19,7 @@
1919
2020from __future__ import absolute_import
2121
22−from unity8.process_helpers import unlock_unity
23−from unity8.shell import with_lightdm_mock, DragMixin
22+from unity8.shell import DragMixin
2423from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
2524
2625from testtools.matchers import Equals
@@ -40,7 +39,6 @@ class TestHud(UnityTestCase, DragMixin):
4039
4140 """
4241 unity_proxy = self.launch_unity()
43− unlock_unity(unity_proxy)
4442 hud_show_button = self.main_window.get_hud_show_button()
4543 edge_drag_area = self.main_window.get_hud_edge_drag_area()
4644 hud = self.main_window.get_hud()
@@ -81,7 +79,6 @@ class TestHud(UnityTestCase, DragMixin):
8179
8280 """
8381 unity_proxy = self.launch_unity()
84− unlock_unity(unity_proxy)
8582 hud_show_button = self.main_window.get_hud_show_button()
8683 hud = self.main_window.get_hud()
8784
@@ -117,7 +114,6 @@ class TestHud(UnityTestCase, DragMixin):
117114 def test_hide_hud_click(self):
118115 """Tapping the close button of the Hud must dismiss it."""
119116 unity_proxy = self.launch_unity()
120− unlock_unity(unity_proxy)
121117 hud = self.main_window.get_hud()
122118
123119 self._launch_test_app_from_app_screen()
@@ -134,7 +130,6 @@ class TestHud(UnityTestCase, DragMixin):
134130
135131 """
136132 unity_proxy = self.launch_unity()
137− unlock_unity(unity_proxy)
138133 hud = self.main_window.get_hud()
139134
140135 self._launch_test_app_from_app_screen()
@@ -151,7 +146,6 @@ class TestHud(UnityTestCase, DragMixin):
151146 def test_launcher_hides_hud(self):
152147 """Opening the Launcher while the Hud is active must close the Hud."""
153148 unity_proxy = self.launch_unity()
154− unlock_unity(unity_proxy)
155149 hud = self.main_window.get_hud()
156150 launcher = self.main_window.get_launcher()
157151
tests/autopilot/unity8/shell/tests/test_emulators.py−3
@@ -34,7 +34,6 @@ except ImportError:
3434
3535from testtools.matchers import Contains, HasLength
3636
37−from unity8 import process_helpers
3837from unity8.shell import emulators, fixture_setup, tests
3938from unity8.shell.emulators import dash as dash_emulators
4039
@@ -46,7 +45,6 @@ class MainWindowTestCase(tests.UnityTestCase):
4645 def setUp(self):
4746 super(MainWindowTestCase, self).setUp()
4847 unity_proxy = self.launch_unity()
49− process_helpers.unlock_unity(unity_proxy)
5048
5149 def test_search(self):
5250 self.main_window.search('Test')
@@ -62,7 +60,6 @@ class DashBaseTestCase(tests.UnityTestCase):
6260 def setUp(self):
6361 super(DashBaseTestCase, self).setUp()
6462 unity_proxy = self.launch_unity()
65− process_helpers.unlock_unity(unity_proxy)
6663 self.dash = self.main_window.get_dash()
6764
6865
tests/autopilot/unity8/shell/tests/test_lock_screen.py+12−13
@@ -20,7 +20,6 @@
2020
2121from __future__ import absolute_import
2222
23−from unity8.process_helpers import unlock_unity
2423from unity8.shell import with_lightdm_mock
2524from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
2625
@@ -47,41 +46,41 @@ class TestLockscreen(UnityTestCase):
4746 @with_lightdm_mock("single-pin")
4847 def test_can_unlock_pin_screen(self):
4948 """Must be able to unlock the PIN entry lock screen."""
50− unity_proxy = self.launch_unity()
49+ self.launch_greeter()
5150 greeter = self.main_window.get_greeter()
5251
5352 if greeter.narrowMode:
54− unlock_unity(unity_proxy)
53+ greeter.swipe()
5554 lockscreen = self._wait_for_lockscreen()
5655 self._enter_pincode("1234")
5756 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
5857 else:
5958 self._enter_prompt_passphrase("1234")
60− self.assertThat(greeter.shown, Eventually(Equals(False)))
59+ self.assertThat(greeter.enabled, Eventually(Equals(False)))
6160
6261 @with_lightdm_mock("single-passphrase")
6362 def test_can_unlock_passphrase_screen(self):
6463 """Must be able to unlock the passphrase entry screen."""
65− unity_proxy = self.launch_unity()
64+ self.launch_greeter()
6665 greeter = self.main_window.get_greeter()
6766
6867 if greeter.narrowMode:
69− unlock_unity(unity_proxy)
68+ greeter.swipe()
7069 lockscreen = self._wait_for_lockscreen()
7170 self._enter_pin_passphrase("password")
7271 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
7372 else:
7473 self._enter_prompt_passphrase("password")
75− self.assertThat(greeter.shown, Eventually(Equals(False)))
74+ self.assertThat(greeter.enabled, Eventually(Equals(False)))
7675
7776 @with_lightdm_mock("single-pin")
7877 def test_pin_screen_wrong_code(self):
7978 """Entering the wrong pin code must not dismiss the lock screen."""
80− unity_proxy = self.launch_unity()
79+ self.launch_greeter()
8180 greeter = self.main_window.get_greeter()
8281
8382 if greeter.narrowMode:
84− unlock_unity(unity_proxy)
83+ greeter.swipe()
8584 lockscreen = self._wait_for_lockscreen()
8685 self._enter_pincode("4321")
8786 pinentryField = self.main_window.get_pinentryField()
@@ -91,16 +90,16 @@ class TestLockscreen(UnityTestCase):
9190 self._enter_prompt_passphrase("4231")
9291 prompt = self.main_window.get_greeter().get_prompt()
9392 self.assertThat(prompt.text, Eventually(Equals("")))
94− self.assertThat(greeter.shown, Eventually(Equals(True)))
93+ self.assertThat(greeter.enabled, Eventually(Equals(True)))
9594
9695 @with_lightdm_mock("single-passphrase")
9796 def test_passphrase_screen_wrong_password(self):
9897 """Entering the wrong password must not dismiss the lock screen."""
99− unity_proxy = self.launch_unity()
98+ self.launch_greeter()
10099 greeter = self.main_window.get_greeter()
101100
102101 if greeter.narrowMode:
103− unlock_unity(unity_proxy)
102+ greeter.swipe()
104103 lockscreen = self._wait_for_lockscreen()
105104 self._enter_pin_passphrase("foobar")
106105 pinentryField = self.main_window.get_pinentryField()
@@ -110,7 +109,7 @@ class TestLockscreen(UnityTestCase):
110109 self._enter_prompt_passphrase("foobar")
111110 prompt = self.main_window.get_greeter().get_prompt()
112111 self.assertThat(prompt.text, Eventually(Equals("")))
113− self.assertThat(greeter.shown, Eventually(Equals(True)))
112+ self.assertThat(greeter.enabled, Eventually(Equals(True)))
114113
115114 def _wait_for_lockscreen(self):
116115 """Wait for the lock screen to load, and return it."""
tests/autopilot/unity8/shell/tests/test_notifications.py+2−14
@@ -22,7 +22,6 @@
2222from __future__ import absolute_import
2323
2424from unity8 import shell
25−from unity8.process_helpers import unlock_unity
2625from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
2726
2827from testtools.matchers import Equals, NotEquals
@@ -125,7 +124,6 @@ class InteractiveNotificationBase(NotificationsBase):
125124 def test_interactive(self):
126125 """Interactive notification must react upon click on itself."""
127126 unity_proxy = self.launch_unity()
128− unlock_unity(unity_proxy)
129127
130128 notify_list = self._get_notifications_list()
131129
@@ -164,7 +162,6 @@ class InteractiveNotificationBase(NotificationsBase):
164162 """Rejecting a call should make notification expand and
165163 offer more options."""
166164 unity_proxy = self.launch_unity()
167− unlock_unity(unity_proxy)
168165
169166 summary = "Incoming call"
170167 body = "Frank Zappa\n+44 (0)7736 027340"
@@ -214,7 +211,6 @@ class InteractiveNotificationBase(NotificationsBase):
214211 def test_modal_sd_without_greeter (self):
215212 """A snap-decision on a phone should block input to shell beneath it when there's no greeter."""
216213 unity_proxy = self.launch_unity()
217− unlock_unity(unity_proxy)
218214
219215 summary = "Incoming file"
220216 body = "Frank would like to send you the file: essay.pdf"
@@ -255,7 +251,7 @@ class InteractiveNotificationBase(NotificationsBase):
255251
256252 def test_modal_sd_with_greeter (self):
257253 """A snap-decision on a phone should not block input to the greeter beneath it."""
258− unity_proxy = self.launch_unity()
254+ unity_proxy = self.launch_greeter()
259255
260256 summary = "Incoming file"
261257 body = "Frank would like to send you the file: essay.pdf"
@@ -281,8 +277,8 @@ class InteractiveNotificationBase(NotificationsBase):
281277
282278 # verify that we can swipe away the greeter (interact with the "shell")
283279 time.sleep(1)
284− self.main_window.show_dash_swiping()
285280 greeter = self.main_window.get_greeter()
281+ greeter.swipe()
286282 self.assertThat(greeter.shown, Eventually(Equals(False)))
287283
288284 # verify and interact with the triggered snap-decision notification
@@ -424,7 +420,6 @@ class EphemeralNotificationsTests(NotificationsBase):
424420 def test_icon_summary_body(self):
425421 """Notification must display the expected summary and body text."""
426422 unity_proxy = self.launch_unity()
427− unlock_unity(unity_proxy)
428423
429424 notify_list = self._get_notifications_list()
430425
@@ -464,7 +459,6 @@ class EphemeralNotificationsTests(NotificationsBase):
464459 """Notification must display the expected summary and secondary
465460 icon."""
466461 unity_proxy = self.launch_unity()
467− unlock_unity(unity_proxy)
468462
469463 notify_list = self._get_notifications_list()
470464
@@ -501,7 +495,6 @@ class EphemeralNotificationsTests(NotificationsBase):
501495 """Notifications must be displayed in order according to their
502496 urgency."""
503497 unity_proxy = self.launch_unity()
504− unlock_unity(unity_proxy)
505498
506499 notify_list = self._get_notifications_list()
507500
@@ -588,7 +581,6 @@ class EphemeralNotificationsTests(NotificationsBase):
588581 def test_summary_and_body(self):
589582 """Notification must display the expected summary- and body-text."""
590583 unity_proxy = self.launch_unity()
591− unlock_unity(unity_proxy)
592584
593585 notify_list = self._get_notifications_list()
594586
@@ -613,7 +605,6 @@ class EphemeralNotificationsTests(NotificationsBase):
613605 def test_summary_only(self):
614606 """Notification must display only the expected summary-text."""
615607 unity_proxy = self.launch_unity()
616− unlock_unity(unity_proxy)
617608
618609 notify_list = self._get_notifications_list()
619610
@@ -631,7 +622,6 @@ class EphemeralNotificationsTests(NotificationsBase):
631622 """Notification must allow updating its contents while being
632623 displayed."""
633624 unity_proxy = self.launch_unity()
634− unlock_unity(unity_proxy)
635625
636626 notify_list = self._get_notifications_list()
637627
@@ -669,7 +659,6 @@ class EphemeralNotificationsTests(NotificationsBase):
669659 """Notification must allow updating its contents and layout while
670660 being displayed."""
671661 unity_proxy = self.launch_unity()
672− unlock_unity(unity_proxy)
673662
674663 notify_list = self._get_notifications_list()
675664
@@ -715,7 +704,6 @@ class EphemeralNotificationsTests(NotificationsBase):
715704 def test_append_hint(self):
716705 """Notification has to accumulate body-text using append-hint."""
717706 unity_proxy = self.launch_unity()
718− unlock_unity(unity_proxy)
719707
720708 notify_list = self._get_notifications_list()
721709
tests/mocks/AccountsService/AccountsService.cpp+9
@@ -45,6 +45,15 @@ void AccountsService::setDemoEdges(bool demoEdges)
4545 Q_UNUSED(demoEdges)
4646}
4747
48+bool AccountsService::demoEdgesForCurrentUser() const
49+{
50+ return false;
51+}
52+
53+void AccountsService::setDemoEdgesForCurrentUser(bool)
54+{
55+}
56+
4857QString AccountsService::backgroundFile() const
4958{
5059 return m_backgroundFile;
tests/mocks/AccountsService/AccountsService.h+7
@@ -35,6 +35,10 @@ class AccountsService: public QObject
3535 READ demoEdges
3636 WRITE setDemoEdges
3737 NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (bool demoEdgesForCurrentUser
39+ READ demoEdgesForCurrentUser
40+ WRITE setDemoEdgesForCurrentUser
41+ NOTIFY demoEdgesForCurrentUserChanged)
3842 Q_PROPERTY (QString backgroundFile
3943 READ backgroundFile
4044 WRITE setBackgroundFile // only available in mock
@@ -51,6 +55,8 @@ public:
5155 void setUser(const QString &user);
5256 bool demoEdges() const;
5357 void setDemoEdges(bool demoEdges);
58+ bool demoEdgesForCurrentUser() const;
59+ void setDemoEdgesForCurrentUser(bool demoEdgesForCurrentUser);
5460 QString backgroundFile() const;
5561 void setBackgroundFile(const QString &backgroundFile);
5662 bool statsWelcomeScreen() const;
@@ -59,6 +65,7 @@ public:
5965Q_SIGNALS:
6066 void userChanged();
6167 void demoEdgesChanged();
68+ void demoEdgesForCurrentUserChanged();
6269 void backgroundFileChanged();
6370 void statsWelcomeScreenChanged();
6471
tests/mocks/CMakeLists.txt+2−1
@@ -31,10 +31,11 @@ endmacro()
3131add_subdirectory(AccountsService)
3232add_subdirectory(GSettings.1.0)
3333add_subdirectory(HudClient)
34+add_subdirectory(liblightdm)
3435add_subdirectory(libusermetrics)
35−add_subdirectory(LightDM)
3636add_subdirectory(Powerd)
3737add_subdirectory(QMenuModel)
38+add_subdirectory(SessionManager)
3839add_subdirectory(Ubuntu)
3940add_subdirectory(Unity)
4041add_subdirectory(QtMultimedia)
tests/mocks/LightDM/CMakeLists.txtdeleted−50
@@ -1,50 +0,0 @@
1−# This is a copy of the normal LightDM plugin, but instead of statically
2−# linking in the lightdm bits, this one uses shared libraries so we can swap
3−# out different sets of users for different tests. When we finally switch to
4−# actually using the system liblightdm in the normal plugin, this version can
5−# be deleted.
6−
7−add_subdirectory(demo)
8−add_subdirectory(full)
9−add_subdirectory(single)
10−add_subdirectory(single-pin)
11−add_subdirectory(single-passphrase)
12−
13−include_directories(
14− ${CMAKE_CURRENT_SOURCE_DIR}
15− ${CMAKE_CURRENT_BINARY_DIR}
16− ${CMAKE_SOURCE_DIR}/plugins/Utils
17− ${CMAKE_SOURCE_DIR}/tests/mocks/libusermetrics
18−)
19−
20−set(QMLPLUGIN_SRC
21− ${CMAKE_SOURCE_DIR}/plugins/LightDM/DBusGreeterList.cpp
22− ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
23− ${CMAKE_SOURCE_DIR}/plugins/LightDM/plugin.cpp
24− ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp
25− ${CMAKE_SOURCE_DIR}/plugins/Utils/qsortfilterproxymodelqml.cpp
26− )
27−
28−add_library(MockLightDM-qml MODULE
29− ${QMLPLUGIN_SRC}
30− )
31−
32−# We want to link to liblightdm-qt5-2, but we don't want to depend on it being
33−# installed on the system. So we make sure we link to our full fake version
34−# At run time, we can point to whichever version we happen to be using via
35−# LD_LIBRARY_PATH.
36−add_dependencies(MockLightDM-qml MockLightDM-full MockUserMetrics)
37−target_link_libraries(MockLightDM-qml
38− -L${CMAKE_CURRENT_BINARY_DIR}/full
39− -llightdm-qt5-2
40− -L${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics
41− -lusermetricsoutput
42− )
43−
44−qt5_use_modules(MockLightDM-qml DBus Gui Qml)
45−
46−add_unity8_mock(LightDM 0.1 LightDM
47− PREFIX mocks
48− TARGETS MockLightDM-qml
49− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}/full"
50−)
tests/mocks/SessionManager/CMakeLists.txtnew file+19
@@ -0,0 +1,19 @@
1+add_library(MockSessionManager-qml MODULE
2+ plugin.cpp
3+ SessionManager.cpp
4+ )
5+
6+qt5_use_modules(MockSessionManager-qml Qml)
7+
8+# copy qmldir file into build directory for shadow builds
9+file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
10+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
11+ )
12+
13+install(TARGETS MockSessionManager-qml
14+ DESTINATION ${SHELL_INSTALL_QML}/mocks/SessionManager
15+ )
16+
17+install(FILES qmldir
18+ DESTINATION ${SHELL_INSTALL_QML}/mocks/SessionManager
19+ )
tests/mocks/SessionManager/SessionManager.cppnew file+43
@@ -0,0 +1,43 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "SessionManager.h"
20+
21+SessionManager::SessionManager(QObject* parent)
22+ : QObject(parent),
23+ m_active(true)
24+{
25+}
26+
27+bool SessionManager::active() const
28+{
29+ return m_active;
30+}
31+
32+void SessionManager::setActive(bool active)
33+{
34+ if (m_active != active) {
35+ m_active = active;
36+ activeChanged();
37+ }
38+}
39+
40+void SessionManager::lock()
41+{
42+ setActive(false);
43+}
tests/mocks/SessionManager/SessionManager.hnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_MOCK_SESSIONMANAGER_H
20+#define UNITY_MOCK_SESSIONMANAGER_H
21+
22+#include <QObject>
23+
24+class SessionManager: public QObject
25+{
26+ Q_OBJECT
27+ Q_PROPERTY(bool active
28+ READ active
29+ WRITE setActive // Only in mock
30+ NOTIFY activeChanged
31+ FINAL)
32+
33+public:
34+ explicit SessionManager(QObject *parent = 0);
35+
36+ bool active() const;
37+ void setActive(bool active);
38+
39+public Q_SLOTS:
40+ void lock();
41+
42+Q_SIGNALS:
43+ void activeChanged();
44+
45+private:
46+ bool m_active;
47+};
48+
49+#endif
tests/mocks/SessionManager/plugin.cppnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "SessionManager.h"
21+#include <QtQml/qqml.h>
22+
23+static QObject *sessionmanager_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
24+{
25+ Q_UNUSED(engine)
26+ Q_UNUSED(scriptEngine)
27+ return new SessionManager();
28+}
29+
30+void SessionManagerPlugin::registerTypes(const char *uri)
31+{
32+ Q_ASSERT(uri == QLatin1String("SessionManager"));
33+ qmlRegisterSingletonType<SessionManager>(uri, 0, 1, "SessionManager", sessionmanager_provider);
34+}
tests/mocks/SessionManager/plugin.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef MOCK_SESSIONMANAGER_PLUGIN_H
20+#define MOCK_SESSIONMANAGER_PLUGIN_H
21+
22+#include <QQmlEngine>
23+#include <QQmlExtensionPlugin>
24+
25+class SessionManagerPlugin : public QQmlExtensionPlugin
26+{
27+ Q_OBJECT
28+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29+
30+public:
31+ void registerTypes(const char *uri);
32+};
33+
34+#endif
tests/mocks/SessionManager/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module SessionManager
2+plugin MockSessionManager-qml
tests/mocks/liblightdm/CMakeLists.txtnew file+4
@@ -0,0 +1,4 @@
1+add_subdirectory(full)
2+add_subdirectory(single)
3+add_subdirectory(single-pin)
4+add_subdirectory(single-passphrase)
tests/mocks/LightDM/Greeter.cpp → tests/mocks/liblightdm/Greeter.cpprenamed+11
@@ -151,12 +151,23 @@ void Greeter::setLanguage (const QString &language)
151151 Q_UNUSED(language)
152152}
153153
154+void Greeter::setResettable (bool resettable)
155+{
156+ Q_UNUSED(resettable)
157+}
158+
154159bool Greeter::startSessionSync(const QString &session)
155160{
156161 Q_UNUSED(session)
157162 return true;
158163}
159164
165+QString Greeter::ensureSharedDataDirSync(const QString &username)
166+{
167+ Q_UNUSED(username)
168+ return "";
169+}
170+
160171void Greeter::respond(const QString &response)
161172{
162173 Q_D(Greeter);
tests/mocks/LightDM/Greeter.h → tests/mocks/liblightdm/Greeter.hrenamed+4
@@ -88,13 +88,17 @@ public Q_SLOTS:
8888 void respond(const QString &response);
8989 void cancelAuthentication();
9090 void setLanguage (const QString &language);
91+ void setResettable (bool resettable);
9192 bool startSessionSync(const QString &session=QString());
93+ QString ensureSharedDataDirSync(const QString &username);
9294
9395Q_SIGNALS:
9496 void showMessage(QString text, QLightDM::Greeter::MessageType type);
9597 void showPrompt(QString text, QLightDM::Greeter::PromptType type);
9698 void authenticationComplete();
9799 void autologinTimerExpired();
100+ void idle();
101+ void reset();
98102
99103private:
100104 GreeterPrivate *d_ptr;
tests/mocks/LightDM/GreeterPrivate.h → tests/mocks/liblightdm/GreeterPrivate.hrenamed

The content is the same.

tests/mocks/LightDM/QLightDM/Greeter → tests/mocks/liblightdm/QLightDM/Greeterrenamed

The content is the same.

tests/mocks/LightDM/QLightDM/InfographicModel → tests/mocks/liblightdm/QLightDM/InfographicModelrenamed

The content is the same.

tests/mocks/LightDM/QLightDM/UsersModel → tests/mocks/liblightdm/QLightDM/UsersModelrenamed

The content is the same.

tests/mocks/LightDM/UsersModel.cpp → tests/mocks/liblightdm/UsersModel.cpprenamed

The content is the same.

tests/mocks/LightDM/UsersModel.h → tests/mocks/liblightdm/UsersModel.hrenamed

The content is the same.

tests/mocks/LightDM/UsersModelPrivate.h → tests/mocks/liblightdm/UsersModelPrivate.hrenamed

The content is the same.

tests/mocks/LightDM/demo/CMakeLists.txt → tests/mocks/liblightdm/demo/CMakeLists.txtrenamed

The content is the same.

tests/mocks/LightDM/demo/GreeterPrivate.cpp → tests/mocks/liblightdm/demo/GreeterPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/demo/UsersModelPrivate.cpp → tests/mocks/liblightdm/demo/UsersModelPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/full/CMakeLists.txt → tests/mocks/liblightdm/full/CMakeLists.txtrenamed+3−2
@@ -11,8 +11,9 @@ add_library(MockLightDM-full SHARED ${LibLightDM_SOURCES})
1111qt5_use_modules(MockLightDM-full Gui)
1212
1313set_target_properties(MockLightDM-full PROPERTIES
14− OUTPUT_NAME lightdm-qt5-2)
14+ OUTPUT_NAME lightdm-qt5-3
15+ SOVERSION 0)
1516
1617install(TARGETS MockLightDM-full
17− DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/full
18+ DESTINATION ${SHELL_INSTALL_QML}/mocks/liblightdm/full
1819 )
tests/mocks/LightDM/full/GreeterPrivate.cpp → tests/mocks/liblightdm/full/GreeterPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/full/UsersModelPrivate.cpp → tests/mocks/liblightdm/full/UsersModelPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/qmldir → tests/mocks/liblightdm/qmldirrenamed

The content is the same.

tests/mocks/LightDM/single-passphrase/CMakeLists.txt → tests/mocks/liblightdm/single-passphrase/CMakeLists.txtrenamed+3−2
@@ -12,8 +12,9 @@ add_library(MockLightDM-single-passphrase SHARED ${LibLightDM_SOURCES})
1212qt5_use_modules(MockLightDM-single-passphrase Gui)
1313
1414set_target_properties(MockLightDM-single-passphrase PROPERTIES
15− OUTPUT_NAME lightdm-qt5-2)
15+ OUTPUT_NAME lightdm-qt5-3
16+ SOVERSION 0)
1617
1718install(TARGETS MockLightDM-single-passphrase
18− DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/single-passphrase
19+ DESTINATION ${SHELL_INSTALL_QML}/mocks/liblightdm/single-passphrase
1920 )
tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpp → tests/mocks/liblightdm/single-passphrase/GreeterPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/single-passphrase/UsersModelPrivate.cpp → tests/mocks/liblightdm/single-passphrase/UsersModelPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/single-pin/CMakeLists.txt → tests/mocks/liblightdm/single-pin/CMakeLists.txtrenamed+3−2
@@ -12,8 +12,9 @@ add_library(MockLightDM-single-pin SHARED ${LibLightDM_SOURCES})
1212qt5_use_modules(MockLightDM-single-pin Gui)
1313
1414set_target_properties(MockLightDM-single-pin PROPERTIES
15− OUTPUT_NAME lightdm-qt5-2)
15+ OUTPUT_NAME lightdm-qt5-3
16+ SOVERSION 0)
1617
1718install(TARGETS MockLightDM-single-pin
18− DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/single-pin
19+ DESTINATION ${SHELL_INSTALL_QML}/mocks/liblightdm/single-pin
1920 )
tests/mocks/LightDM/single-pin/GreeterPrivate.cpp → tests/mocks/liblightdm/single-pin/GreeterPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/single-pin/UsersModelPrivate.cpp → tests/mocks/liblightdm/single-pin/UsersModelPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/single/CMakeLists.txt → tests/mocks/liblightdm/single/CMakeLists.txtrenamed+3−2
@@ -11,8 +11,9 @@ add_library(MockLightDM-single SHARED ${LibLightDM_SOURCES})
1111qt5_use_modules(MockLightDM-single Gui)
1212
1313set_target_properties(MockLightDM-single PROPERTIES
14− OUTPUT_NAME lightdm-qt5-2)
14+ OUTPUT_NAME lightdm-qt5-3
15+ SOVERSION 0)
1516
1617install(TARGETS MockLightDM-single
17− DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/single
18+ DESTINATION ${SHELL_INSTALL_QML}/mocks/liblightdm/single
1819 )
tests/mocks/LightDM/single/GreeterPrivate.cpp → tests/mocks/liblightdm/single/GreeterPrivate.cpprenamed

The content is the same.

tests/mocks/LightDM/single/UsersModelPrivate.cpp → tests/mocks/liblightdm/single/UsersModelPrivate.cpprenamed

The content is the same.

tests/plugins/CMakeLists.txt+2−1
@@ -1,6 +1,7 @@
11add_subdirectory(AccountsService)
2−add_subdirectory(LightDM)
32add_subdirectory(Dash)
3+add_subdirectory(LightDM)
4+add_subdirectory(SessionManager)
45add_subdirectory(Ubuntu)
56add_subdirectory(Unity)
67add_subdirectory(Utils)
tests/plugins/LightDM/CMakeLists.txt+5−4
@@ -1,3 +1,6 @@
1+include(FindPkgConfig)
2+pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-3)
3+
14add_executable(test-lightdm-dbus
25 dbus.cpp
36 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
@@ -7,19 +10,17 @@ qt5_use_modules(test-lightdm-dbus Core DBus Quick Test)
710include_directories(
811 ${CMAKE_CURRENT_BINARY_DIR}
912 ${CMAKE_SOURCE_DIR}/plugins/LightDM
10− ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
1113 ${LIBLIGHTDM_INCLUDE_DIRS}
1214 )
1315
1416add_dependencies(test-lightdm-dbus MockLightDM-full)
1517target_link_libraries(test-lightdm-dbus
16− -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full
17− -llightdm-qt5-2
18+ ${LIBLIGHTDM_LDFLAGS}
1819 )
1920
2021add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
2122
22−add_custom_target(testLightDMDBus dbus-launch env QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full ${CMAKE_CURRENT_BINARY_DIR}/test-lightdm-dbus)
23+add_custom_target(testLightDMDBus dbus-launch env QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/plugins LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full ${CMAKE_CURRENT_BINARY_DIR}/test-lightdm-dbus)
2324add_dependencies(testLightDMDBus test-lightdm-dbus)
2425
2526add_dependencies(qmluitests testLightDMDBus)
tests/plugins/SessionManager/CMakeLists.txtnew file+48
@@ -0,0 +1,48 @@
1+macro(make_dbus_class PREFIX SERVICE INTERFACE)
2+ if (${CMAKE_CURRENT_SOURCE_DIR}/interfaces.xml IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}${INTERFACE}Adaptor.h)
3+ execute_process(COMMAND qdbusxml2cpp -c ${PREFIX}${INTERFACE}Adaptor -a ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}${INTERFACE}Adaptor ${CMAKE_CURRENT_SOURCE_DIR}/interfaces.xml ${SERVICE}.${INTERFACE})
4+ endif ()
5+endmacro(make_dbus_class)
6+
7+make_dbus_class(LightDM org.freedesktop.DisplayManager Session)
8+make_dbus_class(Login org.freedesktop.login1 Manager)
9+make_dbus_class(Login org.freedesktop.login1 Session)
10+make_dbus_class(Login org.freedesktop.DBus Properties)
11+
12+include_directories(
13+ ${CMAKE_CURRENT_BINARY_DIR}
14+ ${CMAKE_SOURCE_DIR}/plugins/SessionManager
15+ )
16+
17+add_definitions(-DSM_BUSNAME=sessionBus)
18+
19+add_executable(sessionmanagermock
20+ ${CMAKE_CURRENT_BINARY_DIR}/LightDMSessionAdaptor.cpp
21+ ${CMAKE_CURRENT_BINARY_DIR}/LoginManagerAdaptor.cpp
22+ ${CMAKE_CURRENT_BINARY_DIR}/LoginPropertiesAdaptor.cpp
23+ ${CMAKE_CURRENT_BINARY_DIR}/LoginSessionAdaptor.cpp
24+ server.cpp
25+ LightDMSessionServer.cpp
26+ LoginManagerServer.cpp
27+ LoginSessionServer.cpp
28+ )
29+qt5_use_modules(sessionmanagermock Core DBus)
30+
31+add_executable(sessionmanagertest
32+ ${CMAKE_SOURCE_DIR}/plugins/SessionManager/SessionManager.cpp
33+ client.cpp
34+ )
35+qt5_use_modules(sessionmanagertest Core DBus Test)
36+
37+add_test(NAME sessionmanagertest
38+ COMMAND env
39+ XDG_SESSION_ID=sessionid
40+ XDG_SESSION_PATH=/mocksession/lightdm
41+ dbus-test-runner
42+ --task ${CMAKE_CURRENT_BINARY_DIR}/sessionmanagermock
43+ --task-name server
44+ --ignore-return
45+ --task ${CMAKE_CURRENT_BINARY_DIR}/sessionmanagertest
46+ --task-name client
47+ --wait-for org.freedesktop.login1
48+ )
tests/plugins/SessionManager/LightDMSessionServer.cppnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LightDMSessionServer.h"
21+
22+LightDMSessionServer::LightDMSessionServer(LoginSessionServer *logind, QObject *parent)
23+ : QObject(parent),
24+ logind(logind)
25+{
26+}
27+
28+void LightDMSessionServer::Lock()
29+{
30+ // As a side effect of locking, change Active state of logind.
31+ // Note that this will say Active is true while the Active property will be
32+ // false. This is intentional, as we don't want to keep any state in the
33+ // mocks. Having this signal side effect lets us test that lock() was
34+ // actually called by the plugin as well as test the changed signal itself.
35+ QVariantMap changes;
36+ changes.insert("Active", QVariant(true));
37+ Q_EMIT logind->PropertiesChanged("org.freedesktop.login1.Session", changes, QStringList());
38+}
tests/plugins/SessionManager/LightDMSessionServer.hnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_LIGHTDMSESSIONSERVER_H
21+#define UNITY_LIGHTDMSESSIONSERVER_H
22+
23+#include "LoginSessionServer.h"
24+#include <QtCore/QObject>
25+
26+class LightDMSessionServer: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit LightDMSessionServer(LoginSessionServer *logind, QObject *parent = 0);
32+
33+public Q_SLOTS:
34+ void Lock();
35+
36+private:
37+ LoginSessionServer *logind;
38+};
39+
40+#endif
tests/plugins/SessionManager/LoginManagerServer.cppnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LoginManagerServer.h"
21+
22+LoginManagerServer::LoginManagerServer(QObject *parent)
23+ : QObject(parent)
24+{
25+}
26+
27+QDBusObjectPath LoginManagerServer::GetSession(const QString &id)
28+{
29+ if (id == "sessionid") {
30+ return QDBusObjectPath("/mocksession/login1");
31+ } else {
32+ return QDBusObjectPath();
33+ }
34+}
tests/plugins/SessionManager/LoginManagerServer.hnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_LOGINMANAGERSERVER_H
21+#define UNITY_LOGINMANAGERSERVER_H
22+
23+#include <QtCore/QObject>
24+#include <QtDBus/QDBusObjectPath>
25+
26+class LoginManagerServer: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit LoginManagerServer(QObject *parent = 0);
32+
33+public Q_SLOTS:
34+ QDBusObjectPath GetSession(const QString &id);
35+};
36+
37+#endif
tests/plugins/SessionManager/LoginSessionServer.cppnew file+25
@@ -0,0 +1,25 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LoginSessionServer.h"
21+
22+LoginSessionServer::LoginSessionServer(QObject *parent)
23+ : QObject(parent)
24+{
25+}
tests/plugins/SessionManager/LoginSessionServer.hnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_LOGINSESSIONSERVER_H
21+#define UNITY_LOGINSESSIONSERVER_H
22+
23+#include <QtCore/QObject>
24+#include <QtCore/QStringList>
25+#include <QtCore/QVariant>
26+#include <QtCore/QVariantMap>
27+
28+class LoginSessionServer: public QObject
29+{
30+ Q_OBJECT
31+
32+public:
33+ explicit LoginSessionServer(QObject *parent = 0);
34+
35+Q_SIGNALS:
36+ void PropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
37+};
38+
39+#endif
tests/plugins/SessionManager/client.cppnew file+88
@@ -0,0 +1,88 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "SessionManager.h"
21+#include <QtTest/QSignalSpy>
22+#include <QtTest/QTest>
23+
24+
25+// These tests assume the following behavior from our mock logind server:
26+// * IsActive will return false
27+// * Lock() will emit an ActiveChanged(true) signal
28+//
29+// This should lead to the following behavior from our SessionManager plugin:
30+// * Starts active
31+// * Becomes inactive once it connects to logind and sees IsActive result
32+// * Becomes active once Lock() is called (which isn't really sensible, but
33+// it's just a mock)
34+
35+class SessionManagerTest : public QObject
36+{
37+ Q_OBJECT
38+
39+private Q_SLOTS:
40+
41+ void waitForChange(SessionManager *session)
42+ {
43+ // Wait 5 seconds for initial activeChanged signal
44+ QSignalSpy spy(session, SIGNAL(activeChanged()));
45+ int i = 0;
46+ while (spy.count() == 0 && i++ < 50)
47+ QTest::qWait(100);
48+ QCOMPARE(spy.count(), 1);
49+ }
50+
51+ void testAssumeActive()
52+ {
53+ // Test that active() starts as true before we connect to service
54+ SessionManager session;
55+ QCOMPARE(session.active(), true);
56+ }
57+
58+ void testSafeLock()
59+ {
60+ // Test that lock() doesn't crash if used before we connect to service
61+ // (i.e. just test that we're not being stupid about pointers)
62+ SessionManager session;
63+ session.lock();
64+ }
65+
66+ void testInitialSignal()
67+ {
68+ // Test that we get notified of change once we connect to service
69+ SessionManager session;
70+ waitForChange(&session);
71+ QCOMPARE(session.active(), false);
72+ }
73+
74+ void testLock()
75+ {
76+ // Test that lock() gets called correctly and that we listen for
77+ // the activeChanged signal too.
78+ SessionManager session;
79+ waitForChange(&session);
80+ session.lock();
81+ waitForChange(&session);
82+ QCOMPARE(session.active(), true);
83+ }
84+};
85+
86+QTEST_MAIN(SessionManagerTest)
87+
88+#include "client.moc"
tests/plugins/SessionManager/interfaces.xmlnew file+22
@@ -0,0 +1,22 @@
1+<node>
2+ <interface name="org.freedesktop.login1.Manager">
3+ <method name="GetSession">
4+ <arg name="id" type="s" direction="in" />
5+ <arg name="path" type="o" direction="out" />
6+ </method>
7+ </interface>
8+ <interface name="org.freedesktop.login1.Session">
9+ <property name="Active" type="b" access="read"/>
10+ </interface>
11+ <interface name="org.freedesktop.DBus.Properties">
12+ <signal name="PropertiesChanged">
13+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
14+ <arg name="interface" type="s" direction="out"/>
15+ <arg name="changed" type="a{sv}" direction="out"/>
16+ <arg name="invalid" type="as" direction="out"/>
17+ </signal>
18+ </interface>
19+ <interface name="org.freedesktop.DisplayManager.Session">
20+ <method name="Lock"/>
21+ </interface>
22+</node>
tests/plugins/SessionManager/server.cppnew file+57
@@ -0,0 +1,57 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LightDMSessionAdaptor.h"
21+#include "LightDMSessionServer.h"
22+#include "LoginManagerAdaptor.h"
23+#include "LoginManagerServer.h"
24+#include "LoginPropertiesAdaptor.h"
25+#include "LoginSessionAdaptor.h"
26+#include "LoginSessionServer.h"
27+#include <QtCore/QCoreApplication>
28+
29+int main(int argc, char *argv[])
30+{
31+ QCoreApplication a(argc, argv);
32+
33+ LoginManagerServer *manager = new LoginManagerServer();
34+ new LoginManagerAdaptor(manager);
35+
36+ LoginSessionServer *l1_session = new LoginSessionServer();
37+ new LoginSessionAdaptor(l1_session);
38+ new LoginPropertiesAdaptor(l1_session);
39+
40+ LightDMSessionServer *ldm_session = new LightDMSessionServer(l1_session);
41+ new LightDMSessionAdaptor(ldm_session);
42+
43+ // We use the session bus for testing. The real plugin uses the system bus
44+ QDBusConnection connection = QDBusConnection::sessionBus();
45+ if (!connection.registerObject("/org/freedesktop/login1", manager))
46+ return 1;
47+ if (!connection.registerObject("/mocksession/login1", l1_session))
48+ return 1;
49+ if (!connection.registerObject("/mocksession/lightdm", ldm_session))
50+ return 1;
51+ if (!connection.registerService("org.freedesktop.DisplayManager"))
52+ return 1;
53+ if (!connection.registerService("org.freedesktop.login1"))
54+ return 1;
55+
56+ return a.exec();
57+}
tests/qmltests/CMakeLists.txt+40−49
@@ -4,6 +4,7 @@ include(QmlTest)
44add_subdirectory(Components)
55
66set(qmltest_DEFAULT_IMPORT_PATHS
7+ ${CMAKE_BINARY_DIR}/plugins
78 ${CMAKE_BINARY_DIR}/tests/utils/modules
89 ${CMAKE_BINARY_DIR}/tests/mocks
910)
@@ -18,12 +19,12 @@ set(qmltest_DEFAULT_TARGETS qmluitests)
1819set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
1920set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
2021
21−add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
22− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
22+add_qml_test(. Shell)
23+add_qml_test(. GreeterShell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/single")
2324add_qml_test(Components Carousel)
2425add_qml_test(Components DraggingArea)
2526add_qml_test(Components EdgeDemoOverlay)
26−add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
27+add_qml_test(Components FilterGrid)
2728add_qml_test(Components LazyImage)
2829add_qml_test(Components Rating)
2930add_qml_test(Components ResponsiveFlowView)
@@ -32,53 +33,43 @@ add_qml_test(Components SeeMore)
3233add_qml_test(Components Showable)
3334add_qml_test(Components PageHeaderLabel)
3435add_qml_test(Components ZoomableImage)
35−add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
36−add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
37−add_qml_test(Dash Card IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
38−add_qml_benchmark(Dash CardBenchmark 1000 IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
39−add_qml_test(Dash CardTool IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
40−add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
41−add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
42− ${CMAKE_BINARY_DIR}/tests/mocks
43− ${CMAKE_BINARY_DIR}/plugins)
44−add_qml_test(Dash/Previews Preview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
45−add_qml_test(Dash/Previews PreviewActions IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
46−add_qml_test(Dash/Previews PreviewAudioPlayback IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
47−add_qml_test(Dash/Previews PreviewHeader IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
48−add_qml_test(Dash/Previews PreviewImageGallery IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
49−add_qml_test(Dash/Previews PreviewProgress IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
50−add_qml_test(Dash/Previews PreviewRatingDisplay IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
51−add_qml_test(Dash/Previews PreviewRatingInput IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
52−add_qml_test(Dash/Previews PreviewTextSummary IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
53−add_qml_test(Dash/Previews PreviewVideoPlayback IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
54−add_qml_test(Dash/Previews PreviewWidgetFactory IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
55−add_qml_test(Dash/Previews PreviewZoomableImage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
56−add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
57− PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
58−add_qml_test(Greeter Tablet IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
59− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
60−add_qml_test(Greeter Phone IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
61− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
62−add_qml_test(Greeter Infographics IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
63− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
64−add_qml_test(Greeter Clock IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
65− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
36+add_qml_test(Dash Dash)
37+add_qml_test(Dash DashContent)
38+add_qml_test(Dash Card)
39+add_qml_benchmark(Dash CardBenchmark 1000)
40+add_qml_test(Dash CardTool)
41+add_qml_test(Dash GenericScopeView)
42+add_qml_test(Dash/Apps RunningApplicationsGrid)
43+add_qml_test(Dash/Previews Preview)
44+add_qml_test(Dash/Previews PreviewActions)
45+add_qml_test(Dash/Previews PreviewAudioPlayback)
46+add_qml_test(Dash/Previews PreviewHeader)
47+add_qml_test(Dash/Previews PreviewImageGallery)
48+add_qml_test(Dash/Previews PreviewProgress)
49+add_qml_test(Dash/Previews PreviewRatingDisplay)
50+add_qml_test(Dash/Previews PreviewRatingInput)
51+add_qml_test(Dash/Previews PreviewTextSummary)
52+add_qml_test(Dash/Previews PreviewVideoPlayback)
53+add_qml_test(Dash/Previews PreviewWidgetFactory)
54+add_qml_test(Dash/Previews PreviewZoomableImage)
55+add_qml_test(Greeter Lockscreen ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
56+add_qml_test(Greeter Tablet ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
57+add_qml_test(Greeter Phone ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/single")
58+add_qml_test(Greeter Infographics ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
59+add_qml_test(Greeter Clock ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
6660add_qml_test(Hud Hud)
6761add_qml_test(Hud Result)
68−add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
69−add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
70−add_qml_test(Notifications VisualSnapDecisionsQueue IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
62+add_qml_test(Launcher Launcher)
63+add_qml_test(Notifications Notifications)
64+add_qml_test(Notifications VisualSnapDecisionsQueue)
7165add_qml_test(Panel IndicatorRow)
72−add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
73−add_qml_test(Panel MenuContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
74−add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
66+add_qml_test(Panel Indicators)
67+add_qml_test(Panel MenuContent)
68+add_qml_test(Panel Panel)
7569add_qml_test(Panel SearchIndicator)
76−add_qml_test(Panel/Indicators DefaultIndicatorWidget IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
77− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
78−add_qml_test(Panel/Indicators DefaultIndicatorPage IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
79− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
80−add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
81−add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
82−add_qml_test(Stages PhoneStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
83− ${CMAKE_BINARY_DIR}/tests/mocks
84− ${CMAKE_BINARY_DIR}/plugins)
70+add_qml_test(Panel/Indicators DefaultIndicatorWidget ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
71+add_qml_test(Panel/Indicators DefaultIndicatorPage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
72+# These MenuItemFactory tests need the test/mocks/ to come before plugins/
73+add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
74+add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
75+add_qml_test(Stages PhoneStage)
tests/qmltests/Greeter/tst_Lockscreen.qml+1−2
@@ -17,7 +17,7 @@
1717import QtQuick 2.0
1818import QtTest 1.0
1919import ".."
20−import "../../../qml/Greeter"
20+import "../../../qml/Components"
2121import Ubuntu.Components 0.1
2222import LightDM 0.1 as LightDM
2323import Unity.Test 0.1 as UT
@@ -39,7 +39,6 @@ Rectangle {
3939 minPinLength: minPinLengthTextField.text
4040 maxPinLength: maxPinLengthTextField.text
4141 username: "Lola"
42− background: "../../../qml/graphics/phone_background.jpg"
4342 infoText: infoTextTextField.text
4443 }
4544
tests/qmltests/Greeter/tst_Phone.qml+1−17
@@ -33,7 +33,7 @@ Item {
3333 height: parent.height
3434 x: 0; y: 0
3535
36− defaultBackground: Qt.resolvedUrl("../../../qml/graphics/phone_background.jpg")
36+ background: Qt.resolvedUrl("../../../qml/graphics/phone_background.jpg")
3737
3838 property int minX: 0
3939
@@ -104,22 +104,6 @@ Item {
104104 tryCompare(LightDM.Infographic, "username", "single")
105105 }
106106
107− function test_background_data() {
108− return [
109− {tag: "set", accounts: Qt.resolvedUrl("../../data/unity/backgrounds/blue.png"), expected: "blue.png"},
110− {tag: "unset", accounts: "", expected: "background.jpg"},
111− {tag: "invalid", accounts: "invalid", expected: "background.jpg"},
112− ]
113− }
114−
115− function test_background(data) {
116− var loader = findChild(greeter, "greeterContentLoader")
117− var background = findChild(loader.item, "greeterBackground")
118− AccountsService.backgroundFile = data.accounts
119− tryCompareFunction(function() { return background.source.toString().indexOf(data.expected) !== -1; }, true)
120− tryCompare(background, "status", Image.Ready)
121− }
122−
123107 function test_initial_selected_signal() {
124108 var greeterObj = greeterComponent.createObject(this)
125109 var spy = findChild(greeterObj, "selectedSpy")
tests/qmltests/tst_GreeterShell.qmlnew file+88
@@ -0,0 +1,88 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michael Terry <michael.terry@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+import QtQuick 2.0
21+import QtTest 1.0
22+import AccountsService 0.1
23+import GSettings 1.0
24+import Unity.Application 0.1
25+import Unity.Test 0.1 as UT
26+import Powerd 0.1
27+import LightDM 0.1 as LightDM
28+
29+import "../../qml"
30+
31+Item {
32+ width: shell.width
33+ height: shell.height
34+
35+ QtObject {
36+ id: applicationArguments
37+
38+ function hasGeometry() {
39+ return false;
40+ }
41+
42+ function width() {
43+ return 0;
44+ }
45+
46+ function height() {
47+ return 0;
48+ }
49+ }
50+
51+ GreeterShell {
52+ id: shell
53+ defaultBackground: Qt.resolvedUrl("../../qml/graphics/phone_background.jpg")
54+ }
55+
56+ UT.UnityTestCase {
57+ name: "GreeterShell"
58+ when: windowShown
59+
60+ function test_wallpaper_data() {
61+ return [
62+ {tag: "both", accounts: "../tests/data/unity/backgrounds/blue.png", gsettings: "../tests/data/unity/backgrounds/red.png", expected: "blue.png"},
63+ {tag: "accounts", accounts: "../tests/data/unity/backgrounds/blue.png", gsettings: "", expected: "blue.png"},
64+ {tag: "gsettings", accounts: "", gsettings: "../tests/data/unity/backgrounds/red.png", expected: "red.png"},
65+ {tag: "none", accounts: "", gsettings: "", expected: shell.defaultBackground},
66+ {tag: "invalid-both", accounts: "invalid", gsettings: "invalid", expected: shell.defaultBackground},
67+ {tag: "invalid-accounts", accounts: "invalid", gsettings: "../tests/data/unity/backgrounds/red.png", expected: shell.defaultBackground},
68+ {tag: "invalid-gsettings", accounts: "../tests/data/unity/backgrounds/blue.png", gsettings: "invalid", expected: "blue.png"},
69+ ]
70+ }
71+
72+ function test_wallpaper(data) {
73+ var greeterBackground = findChild(shell, "greeterBackground")
74+ GSettingsController.setPictureUri(data.gsettings)
75+ AccountsService.backgroundFile = data.accounts
76+ verify(greeterBackground.source.toString().indexOf(data.expected) !== -1)
77+ tryCompare(greeterBackground, "status", Image.Ready)
78+ }
79+
80+ function test_dispatchURLHidesGreeter() {
81+ var greeter = findChild(shell, "greeter")
82+ greeter.showNow()
83+ tryCompare(greeter, "showProgress", 1)
84+ LightDM.URLDispatcher.dispatchURL("application:///notes-app")
85+ tryCompare(greeter, "showProgress", 0)
86+ }
87+ }
88+}
tests/qmltests/tst_Shell.qml+10−64
@@ -23,6 +23,7 @@ import GSettings 1.0
2323import Unity.Application 0.1
2424import Unity.Test 0.1 as UT
2525import Powerd 0.1
26+import SessionManager 0.1
2627
2728import "../../qml"
2829
@@ -48,6 +49,7 @@ Item {
4849
4950 Shell {
5051 id: shell
52+ defaultBackground: Qt.resolvedUrl("../../qml/graphics/phone_background.jpg")
5153 }
5254
5355 UT.UnityTestCase {
@@ -72,9 +74,6 @@ Item {
7274 ok = homeLoader !== null
7375 && homeLoader.item !== undefined;
7476
75− var greeter = findChild(shell, "greeter");
76− ok &= greeter !== null;
77−
7877 var launcherPanel = findChild(shell, "launcherPanel");
7978 ok &= launcherPanel !== null;
8079
@@ -89,17 +88,9 @@ Item {
8988 } while (!ok && attempts <= maxAttempts);
9089
9190 verify(ok);
92−
93− swipeAwayGreeter();
9491 }
9592
9693 function cleanup() {
97− // If a test invoked the greeter, make sure we swipe it away again
98− var greeter = findChild(shell, "greeter");
99− if (greeter.shown) {
100− swipeAwayGreeter();
101− }
102−
10394 // kill all (fake) running apps
10495 killApps(ApplicationManager);
10596
@@ -181,8 +172,6 @@ Item {
181172 }
182173
183174 function test_suspend() {
184− var greeter = findChild(shell, "greeter");
185−
186175 // Launch an app from the launcher
187176 dragLauncherIntoView();
188177 tapOnAppIconInLauncher();
@@ -196,40 +185,27 @@ Item {
196185
197186 // Try to suspend while proximity is engaged...
198187 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
199− tryCompare(greeter, "showProgress", 0);
188+ tryCompare(SessionManager, "active", true);
200189
201190 // Now really suspend
202191 print("suspending")
203192 Powerd.displayPowerStateChange(Powerd.Off, 0);
204193 print("done suspending")
205− tryCompare(greeter, "showProgress", 1);
194+ tryCompare(SessionManager, "active", false);
206195
207196 tryCompare(ApplicationManager, "suspended", true);
208197 compare(mainApp.state, ApplicationInfo.Suspended);
209198
210199 // And wake up
211200 Powerd.displayPowerStateChange(Powerd.On, 0);
212− tryCompare(greeter, "showProgress", 1);
213201
214− // Swipe away greeter to focus app
215− swipeAwayGreeter();
202+ // Activate session to focus app
203+ SessionManager.active = true;
216204 tryCompare(ApplicationManager, "suspended", false);
217205 compare(mainApp.state, ApplicationInfo.Running);
218206 tryCompare(ApplicationManager, "focusedApplicationId", mainAppId);
219207 }
220208
221− function swipeAwayGreeter() {
222− var greeter = findChild(shell, "greeter");
223− tryCompare(greeter, "showProgress", 1);
224−
225− var touchX = shell.width - (shell.edgeSize / 2);
226− var touchY = shell.height / 2;
227− touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
228−
229− // wait until the animation has finished
230− tryCompare(greeter, "showProgress", 0);
231− }
232−
233209 /*
234210 Perform a right-edge drag when the Dash is being show and there are
235211 no running/minimized apps to be restored.
@@ -477,22 +453,14 @@ Item {
477453
478454 function test_DashShown_data() {
479455 return [
480− {tag: "in focus", greeter: false, app: false, launcher: false, indicators: false, expectedShown: true},
481− {tag: "under greeter", greeter: true, app: false, launcher: false, indicators: false, expectedShown: false},
482− {tag: "under app", greeter: false, app: true, launcher: false, indicators: false, expectedShown: false},
483− {tag: "under launcher", greeter: false, app: false, launcher: true, indicators: false, expectedShown: true},
484− {tag: "under indicators", greeter: false, app: false, launcher: false, indicators: true, expectedShown: true},
456+ {tag: "in focus", app: false, launcher: false, indicators: false, expectedShown: true},
457+ {tag: "under app", app: true, launcher: false, indicators: false, expectedShown: false},
458+ {tag: "under launcher", app: false, launcher: true, indicators: false, expectedShown: true},
459+ {tag: "under indicators", app: false, launcher: false, indicators: true, expectedShown: true},
485460 ]
486461 }
487462
488463 function test_DashShown(data) {
489− if (data.greeter) {
490− // Swipe the greeter in
491− var greeter = findChild(shell, "greeter");
492− Powerd.displayPowerStateChange(Powerd.Off, 0);
493− tryCompare(greeter, "showProgress", 1);
494− }
495−
496464 if (data.app) {
497465 dragLauncherIntoView();
498466 tapOnAppIconInLauncher();
@@ -522,17 +490,6 @@ Item {
522490 tryCompare(searchIndicator, "opacity", 0);
523491 }
524492
525− function test_searchIndicatorHidesOnGreeterShown() {
526− var searchIndicator = findChild(shell, "container")
527− var greeter = findChild(shell, "greeter");
528−
529− tryCompare(searchIndicator, "opacity", 1)
530−
531− greeter.show()
532− tryCompare(greeter, "shown", true)
533− tryCompare(searchIndicator, "opacity", 0)
534− }
535−
536493 function test_searchIndicatorHideOnPreviewShown() {
537494 var searchIndicator = findChild(shell, "container");
538495 var dashContent = findChild(shell, "dashContent");
@@ -545,16 +502,5 @@ Item {
545502
546503 tryCompare(searchIndicator, "opacity", 0);
547504 }
548−
549− function test_focusRequestedHidesGreeter() {
550− var greeter = findChild(shell, "greeter")
551−
552− greeter.show()
553− tryCompare(greeter, "showProgress", 1)
554−
555− ApplicationManager.focusRequested("notes-app")
556− tryCompare(greeter, "showProgress", 0)
557− waitUntilApplicationWindowIsFullyVisible()
558− }
559505 }
560506}
tools/unlock-device+10−18
@@ -17,24 +17,16 @@ while getopts s:w: opt; do
1717 esac
1818done
1919
20−UNLOCK_SCRIPT='
21−import dbus, logging;
22−from unity8 import process_helpers as helpers;
23−logging.basicConfig(level=logging.INFO);
24−bus = dbus.SystemBus().get_object("com.canonical.powerd", "/com/canonical/powerd");
25−cookie = bus.requestSysState("unlock-device-hold", 1, dbus_interface="com.canonical.powerd");
26−helpers.restart_unity_with_testability();
27−bus.clearSysState(cookie, dbus_interface="com.canonical.powerd");
28−helpers.unlock_unity()
29−'
20+LIGHTDM_CONFIG="
21+[SeatDefaults]
22+autologin-in-background=false
23+"
24+LIGHTDM_CONFIG_FILE="/etc/lightdm/lightdm.conf.d/99-unity8-greeter-unlock.conf"
25+
26+adb shell "echo '$LIGHTDM_CONFIG' > $LIGHTDM_CONFIG_FILE"
3027
3128eval "$WAIT_COMMAND"
3229
33−UNLOCK_OUTPUT=$(adb shell "sudo -u phablet -i python3 -c '$UNLOCK_SCRIPT'" 2>&1)
34−if echo "$UNLOCK_OUTPUT" | grep 'Greeter unlocked' >/dev/null; then
35− echo "I: Unlock passed"
36− exit 0
37−else
38− echo "I: Unlock failed, script output: '$UNLOCK_OUTPUT'"
39− exit 1
40−fi
30+adb shell "rm -f $LIGHTDM_CONFIG_FILE"
31+
32+exit 0