on xenial help sign in
Revert split greeter. This gives us back the integrated greeter for Touch images, to reduce the level of regressions we are seeing.
90a3940Michael Terry
CMakeLists.txt−1
@@ -96,7 +96,6 @@ include(autopilot)
96declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
96declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
97
97
98set(SHELL_APP unity8)
98set(SHELL_APP unity8)
99−set(GREETER_APP unity8-greeter)
100set(SCOPE_TOOL unity-scope-tool)
99set(SCOPE_TOOL unity-scope-tool)
101
100
102include_directories(
101include_directories(
data/51-unity8-greeter.confdeleted−2
@@ -1,2 +0,0 @@
1−[SeatDefaults]
2−greeter-session=unity8-greeter
data/CMakeLists.txt−13
@@ -1,20 +1,7 @@
1# generate desktop file
1# generate desktop file
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
2configure_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)
4
3
5# install desktop files
4# install desktop files
6install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
5install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
7 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
6 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
8 )
7 )
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 ${GREETER_APP}-logrotate.conf
19− DESTINATION ${CMAKE_INSTALL_DATADIR}/upstart/sessions
20− )
data/unity8-greeter-init.confdeleted−12
@@ -1,12 +0,0 @@
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-wrapperdeleted−109
@@ -1,109 +0,0 @@
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 "$DBUS_PID" ]; then
28− kill "$DBUS_PID"
29− fi
30− if [ -n "$CMD_PID" ]; then
31− kill "$CMD_PID"
32− fi
33− exit 0
34−}
35−
36−set_greeter_var()
37−{
38− export "$1=$2"
39− gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "{'$1': '$2'}"
40− if [ -n "$INIT_PID" ]; then
41− initctl set-env --global "$1=$2"
42− fi
43−}
44−
45−# Start dbus if it hasn't already been started for us (such as on the Desktop
46−# images by dbus-launch). We don't want to use dbus-launch ourselves because
47−# we don't want dbus-x11 on the Touch images.
48−if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
49− export DBUS_SESSION_BUS_ADDRESS=unix:abstract=$(mktemp -u /tmp/dbus-XXXXXXXXXX)
50− DBUS_PID=$(dbus-daemon --fork --session --print-pid --address="$DBUS_SESSION_BUS_ADDRESS")
51−fi
52−
53−SUB_SOCKET=$XDG_RUNTIME_DIR/mir_socket
54−rm -f $SUB_SOCKET # clear socket in case we were hard shut down
55−
56−# If touch session script (which sets up grid units and mir variables) is available, use it
57−TOUCH_WRAPPER=
58−if [ -x /usr/bin/ubuntu-touch-session ]; then
59− TOUCH_WRAPPER=/usr/bin/ubuntu-touch-session
60−fi
61−
62−# Pretend that we're in an ubuntu-touch session, so that indicator-network
63−# will start.
64−export DESKTOP_SESSION=ubuntu-touch
65−
66−# We disable ofono using pulse. It causes problems with racing with the user's
67−# pulse. We need to come up with a better long-term fix for this, because we
68−# eventually need the greeter to play ringtones for users that aren't logged in.
69−set_greeter_var PA_DISABLED 1
70−
71−# Normal unity8 sessions are entirely driven by Upstart. But greeters
72−# are special. They need access to the file descriptors that lightdm
73−# creates for them and don't want to start all the services that a normal
74−# session would. So it's inconvenient to live within an upstart session.
75−# But... we still want to use Upstart for some services. So launch here.
76−USC_SOCKET=$MIR_SOCKET MIR_SOCKET=$SUB_SOCKET $TOUCH_WRAPPER /sbin/init --user --no-startup-event &
77−INIT_PID=$!
78−while [ ! -e "$XDG_RUNTIME_DIR/upstart/sessions/$INIT_PID.session" ]; do sleep 0.1; done
79−export UPSTART_SESSION=$(/sbin/initctl list-sessions | grep "^$INIT_PID " | cut -d' ' -f2)
80−
81−# Start any pre-greeter tasks if needed (like wizard)
82−/sbin/initctl emit unity8-greeter-starting
83−
84−# Define language here for phone if available. When phone user switches their
85−# language, they expect that to affect the greeter too. But the user doesn't
86−# have permission to switch system language, only their own. So we notice if
87−# the phablet user exists and use their language if so. TODO: talk to design
88−# about whether we should switch language on fly as users are selected (this
89−# is very hard to do technically).
90−#
91−# Do this after unity8-greeter-starting, in case a customization upstart job
92−# changes language.
93−if [ "$(id -u phablet 2>/dev/null)" = "32011" ]; then
94− 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)
95− if [ -n "$USER_LANG" ]; then
96− set_greeter_var LANGUAGE "$USER_LANG"
97− fi
98− 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)
99− if [ -n "$USER_LOCALE" ]; then
100− set_greeter_var LANG "$USER_LOCALE"
101− set_greeter_var LC_ALL "$USER_LOCALE"
102− fi
103−fi
104−
105−# And finally actually start the greeter
106−exec env MIR_SERVER_FILE=$SUB_SOCKET $TOUCH_WRAPPER $@ &
107−CMD_PID=$!
108−wait $CMD_PID
109−CMD_PID=
data/unity8-greeter.desktop.indeleted−5
@@ -1,5 +0,0 @@
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+8
@@ -1,3 +1,11 @@
1+unity8 (7.89) UNRELEASED; urgency=medium
2+
3+ * Revert split greeter for now. We will bring it back as an option
4+ for Desktop, but use a big hammer revert right now to get Touch back
5+ in shape.
6+
7+ -- Michael Terry <mterry@ubuntu.com> Wed, 11 Jun 2014 11:39:12 -0400
8+
1unity8 (7.88+14.10.20140606-0ubuntu1) utopic; urgency=low
9unity8 (7.88+14.10.20140606-0ubuntu1) utopic; urgency=low
2
10
3 [ Michał Sawicz ]
11 [ Michał Sawicz ]
debian/control+2−15
@@ -14,7 +14,6 @@ Build-Depends: cmake,
14 libglib2.0-dev,
14 libglib2.0-dev,
15 libgsettings-qt-dev,
15 libgsettings-qt-dev,
16 libhud-client2-dev,
16 libhud-client2-dev,
17− liblightdm-qt5-3-dev (>= 1.11.1),
18 libpulse-dev,
17 libpulse-dev,
19 libqmenumodel-dev (>= 0.2.7),
18 libqmenumodel-dev (>= 0.2.7),
20 libqt5xmlpatterns5-dev,
19 libqt5xmlpatterns5-dev,
@@ -80,7 +79,6 @@ Depends: gsettings-desktop-schemas,
80 qml-module-qtquick-xmllistmodel,
79 qml-module-qtquick-xmllistmodel,
81 qtdeclarative5-gsettings1.0,
80 qtdeclarative5-gsettings1.0,
82 qtdeclarative5-ubuntu-settings-components,
81 qtdeclarative5-ubuntu-settings-components,
83− unity-greeter-session-broadcast,
84 unity-launcher-impl-3,
82 unity-launcher-impl-3,
85 unity8-common (= ${source:Version}),
83 unity8-common (= ${source:Version}),
86 unity8-private (= ${binary:Version}),
84 unity8-private (= ${binary:Version}),
@@ -92,22 +90,12 @@ Recommends: unity-scope-click,
92 unity-scope-scopes,
90 unity-scope-scopes,
93Breaks: indicator-network (<< 0.5.1),
91Breaks: indicator-network (<< 0.5.1),
94 ubuntu-touch-session (<< 0.107),
92 ubuntu-touch-session (<< 0.107),
93+ unity8-greeter (<< 7.89),
95Replaces: ubuntu-touch-session (<< 0.82~),
94Replaces: ubuntu-touch-session (<< 0.82~),
95+ unity8-greeter (<< 7.89),
96Description: Unity 8 shell
96Description: Unity 8 shell
97 The Unity 8 shell is the primary user interface for Ubuntu devices.
97 The Unity 8 shell is the primary user interface for Ubuntu devices.
98
98
99−Package: unity8-greeter
100−Architecture: any
101−Depends: libglib2.0-bin,
102− lightdm,
103− unity8 (= ${source:Version}),
104− ${misc:Depends},
105− ${shlibs:Depends},
106−Breaks: unity8 (<< 7.87),
107−Replaces: unity8 (<< 7.87),
108−Description: Ubuntu QML greeter
109− The Ubuntu QML greeter is the primary greeter for Ubuntu devices.
110−
111Package: unity8-common
99Package: unity8-common
112Architecture: all
100Architecture: all
113Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
101Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
@@ -146,7 +134,6 @@ Depends: gir1.2-glib-2.0,
146 ubuntu-ui-toolkit-autopilot,
134 ubuntu-ui-toolkit-autopilot,
147 unity8 (= ${source:Version}),
135 unity8 (= ${source:Version}),
148 unity8-fake-env (= ${source:Version}),
136 unity8-fake-env (= ${source:Version}),
149− unity8-greeter (= ${source:Version}),
150 url-dispatcher-tools,
137 url-dispatcher-tools,
151 ${misc:Depends},
138 ${misc:Depends},
152 ${python3:Depends},
139 ${python3:Depends},
debian/copyright+1−1
@@ -22,7 +22,7 @@ License: GPL-3
22 On Debian systems, the full text of the GNU General Public License
22 On Debian systems, the full text of the GNU General Public License
23 version 3 can be found in the file /usr/share/common-licenses/GPL-3.
23 version 3 can be found in the file /usr/share/common-licenses/GPL-3.
24
24
25−Files: tests/mocks/liblightdm/UsersModel.h tests/mocks/liblightdm/Greeter.h
25+Files: tests/mocks/LightDM/UsersModel.h tests/mocks/LightDM/Greeter.h
26Copyright: 2013 Canonical Ltd.
26Copyright: 2013 Canonical Ltd.
27 2010-2011 David Edmundson
27 2010-2011 David Edmundson
28 2010-2011 Robert Ancell
28 2010-2011 Robert Ancell
debian/rules+4
@@ -34,3 +34,7 @@ override_dh_install:
34# use private lib directories
34# use private lib directories
35override_dh_makeshlibs:
35override_dh_makeshlibs:
36 dh_makeshlibs -Nunity8-private -Nunity8-fake-env
36 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.installdeleted−6
@@ -1,6 +0,0 @@
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,7 +4,6 @@ usr/lib/*/unity8/qml/HudClient
4usr/lib/*/unity8/qml/LightDM
4usr/lib/*/unity8/qml/LightDM
5usr/lib/*/unity8/qml/Powerd
5usr/lib/*/unity8/qml/Powerd
6usr/lib/*/unity8/qml/SessionBroadcast
6usr/lib/*/unity8/qml/SessionBroadcast
7−usr/lib/*/unity8/qml/SessionManager
8usr/lib/*/unity8/qml/Ubuntu
7usr/lib/*/unity8/qml/Ubuntu
9usr/lib/*/unity8/qml/Unity
8usr/lib/*/unity8/qml/Unity
10usr/lib/*/unity8/qml/Utils
9usr/lib/*/unity8/qml/Utils
debian/unity8.install+1
@@ -1,6 +1,7 @@
1data/unity8.conf usr/share/upstart/sessions/
1data/unity8.conf usr/share/upstart/sessions/
2usr/bin/unity8
2usr/bin/unity8
3usr/share/applications/unity8.desktop
3usr/share/applications/unity8.desktop
4+usr/share/unity8/Greeter
4usr/share/unity8/Hud
5usr/share/unity8/Hud
5usr/share/unity8/Launcher
6usr/share/unity8/Launcher
6usr/share/unity8/Panel
7usr/share/unity8/Panel
plugins/AccountsService/AccountsService.cpp+11−34
@@ -24,6 +24,7 @@
24AccountsService::AccountsService(QObject* parent)
24AccountsService::AccountsService(QObject* parent)
25 : QObject(parent),
25 : QObject(parent),
26 m_service(new AccountsServiceDBusAdaptor(this)),
26 m_service(new AccountsServiceDBusAdaptor(this)),
27+ m_user(qgetenv("USER")),
27 m_demoEdges(false),
28 m_demoEdges(false),
28 m_statsWelcomeScreen(false)
29 m_statsWelcomeScreen(false)
29{
30{
@@ -31,9 +32,6 @@ AccountsService::AccountsService(QObject* parent)
31 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
32 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
32 connect(m_service, SIGNAL(maybeChanged(const QString &)),
33 connect(m_service, SIGNAL(maybeChanged(const QString &)),
33 this, SLOT(maybeChanged(const QString &)));
34 this, SLOT(maybeChanged(const QString &)));
34−
35− setUser(qgetenv("USER"));
36− updateDemoEdgesForCurrentUser();
37}
35}
38
36
39QString AccountsService::user() const
37QString AccountsService::user() const
@@ -59,22 +57,9 @@ bool AccountsService::demoEdges() const
59void AccountsService::setDemoEdges(bool demoEdges)
57void AccountsService::setDemoEdges(bool demoEdges)
60{
58{
61 m_demoEdges = demoEdges;
59 m_demoEdges = demoEdges;
62− Q_EMIT demoEdgesChanged();
63 m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
60 m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
64}
61}
65
62
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−
78QString AccountsService::backgroundFile() const
63QString AccountsService::backgroundFile() const
79{
64{
80 return m_backgroundFile;
65 return m_backgroundFile;
@@ -94,15 +79,6 @@ void AccountsService::updateDemoEdges()
94 }
79 }
95}
80}
96
81
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−
106void AccountsService::updateBackgroundFile()
82void AccountsService::updateBackgroundFile()
107{
83{
108 auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
84 auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
@@ -123,14 +99,13 @@ void AccountsService::updateStatsWelcomeScreen()
123
99
124void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
100void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
125{
101{
102+ if (m_user != user) {
103+ return;
104+ }
105+
126 if (interface == "com.canonical.unity.AccountsService") {
106 if (interface == "com.canonical.unity.AccountsService") {
127 if (changed.contains("demo-edges")) {
107 if (changed.contains("demo-edges")) {
128− if (qgetenv("USER") == user) {
129− updateDemoEdgesForCurrentUser();
130− }
131− if (m_user == user) {
132− updateDemoEdges();
108+ updateDemoEdges();
133− }
134 }
109 }
135 } else if (interface == "com.ubuntu.touch.AccountsService.SecurityPrivacy") {
110 } else if (interface == "com.ubuntu.touch.AccountsService.SecurityPrivacy") {
136 if (changed.contains("StatsWelcomeScreen")) {
111 if (changed.contains("StatsWelcomeScreen")) {
@@ -141,8 +116,10 @@ void AccountsService::propertiesChanged(const QString &user, const QString &inte
141
116
142void AccountsService::maybeChanged(const QString &user)
117void AccountsService::maybeChanged(const QString &user)
143{
118{
144− if (m_user == user) {
119+ if (m_user != user) {
145− // Standard properties might have changed
120+ return;
146− updateBackgroundFile();
147 }
121 }
122+
123+ // Standard properties might have changed
124+ updateBackgroundFile();
148}
125}
plugins/AccountsService/AccountsService.h−9
@@ -35,10 +35,6 @@ class AccountsService: public QObject
35 READ demoEdges
35 READ demoEdges
36 WRITE setDemoEdges
36 WRITE setDemoEdges
37 NOTIFY demoEdgesChanged)
37 NOTIFY demoEdgesChanged)
38− Q_PROPERTY (bool demoEdgesForCurrentUser
39− READ demoEdgesForCurrentUser
40− WRITE setDemoEdgesForCurrentUser
41− NOTIFY demoEdgesForCurrentUserChanged)
42 Q_PROPERTY (QString backgroundFile
38 Q_PROPERTY (QString backgroundFile
43 READ backgroundFile
39 READ backgroundFile
44 NOTIFY backgroundFileChanged)
40 NOTIFY backgroundFileChanged)
@@ -53,15 +49,12 @@ public:
53 void setUser(const QString &user);
49 void setUser(const QString &user);
54 bool demoEdges() const;
50 bool demoEdges() const;
55 void setDemoEdges(bool demoEdges);
51 void setDemoEdges(bool demoEdges);
56− bool demoEdgesForCurrentUser() const;
57− void setDemoEdgesForCurrentUser(bool demoEdgesForCurrentUser);
58 QString backgroundFile() const;
52 QString backgroundFile() const;
59 bool statsWelcomeScreen() const;
53 bool statsWelcomeScreen() const;
60
54
61Q_SIGNALS:
55Q_SIGNALS:
62 void userChanged();
56 void userChanged();
63 void demoEdgesChanged();
57 void demoEdgesChanged();
64− void demoEdgesForCurrentUserChanged();
65 void backgroundFileChanged();
58 void backgroundFileChanged();
66 void statsWelcomeScreenChanged();
59 void statsWelcomeScreenChanged();
67
60
@@ -71,14 +64,12 @@ private Q_SLOTS:
71
64
72private:
65private:
73 void updateDemoEdges();
66 void updateDemoEdges();
74− void updateDemoEdgesForCurrentUser();
75 void updateBackgroundFile();
67 void updateBackgroundFile();
76 void updateStatsWelcomeScreen();
68 void updateStatsWelcomeScreen();
77
69
78 AccountsServiceDBusAdaptor *m_service;
70 AccountsServiceDBusAdaptor *m_service;
79 QString m_user;
71 QString m_user;
80 bool m_demoEdges;
72 bool m_demoEdges;
81− bool m_demoEdgesForCurrentUser;
82 QString m_backgroundFile;
73 QString m_backgroundFile;
83 bool m_statsWelcomeScreen;
74 bool m_statsWelcomeScreen;
84};
75};
plugins/CMakeLists.txt−1
@@ -17,7 +17,6 @@ add_subdirectory(LightDM)
17add_subdirectory(Dash)
17add_subdirectory(Dash)
18add_subdirectory(Powerd)
18add_subdirectory(Powerd)
19add_subdirectory(SessionBroadcast)
19add_subdirectory(SessionBroadcast)
20−add_subdirectory(SessionManager)
21add_subdirectory(Ubuntu)
20add_subdirectory(Ubuntu)
22add_subdirectory(Unity)
21add_subdirectory(Unity)
23add_subdirectory(Utils)
22add_subdirectory(Utils)
plugins/LightDM/CMakeLists.txt+9−6
@@ -1,22 +1,23 @@
1# Dependencies
1# Dependencies
2include(FindPkgConfig)
2include(FindPkgConfig)
3−pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-3)
4pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
3pkg_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)
5
6
6include_directories(
7include_directories(
7 ${CMAKE_CURRENT_SOURCE_DIR}
8 ${CMAKE_CURRENT_SOURCE_DIR}
8 ${CMAKE_CURRENT_BINARY_DIR}
9 ${CMAKE_CURRENT_BINARY_DIR}
9 ${CMAKE_SOURCE_DIR}/plugins/Utils
10 ${CMAKE_SOURCE_DIR}/plugins/Utils
11+ ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
10− ${LIBLIGHTDM_INCLUDE_DIRS}
12+ #${LIBLIGHTDM_INCLUDE_DIRS}
11 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
13 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
12)
14)
13
15
14set(QMLPLUGIN_SRC
16set(QMLPLUGIN_SRC
15− ${CMAKE_SOURCE_DIR}/plugins/Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
17+ ../Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
16 DBusGreeterList.cpp
18 DBusGreeterList.cpp
17 Greeter.cpp
19 Greeter.cpp
18 plugin.cpp
20 plugin.cpp
19− URLDispatcher.cpp
20 UsersModel.cpp
21 UsersModel.cpp
21 )
22 )
22
23
@@ -25,10 +26,12 @@ add_library(LightDM-qml MODULE
25 )
26 )
26
27
27target_link_libraries(LightDM-qml
28target_link_libraries(LightDM-qml
29+ MockLightDM-demo
30+# TODO: Once we split out a separate greeter process, uncomment these lines
28− ${LIBLIGHTDM_LDFLAGS}
31+# ${LIBLIGHTDM_LDFLAGS}
29 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
32 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
30 )
33 )
31
34
32−qt5_use_modules(LightDM-qml DBus Qml)
35+qt5_use_modules(LightDM-qml DBus Gui Qml)
33
36
34add_unity8_plugin(LightDM 0.1 LightDM TARGETS LightDM-qml)
37add_unity8_plugin(LightDM 0.1 LightDM TARGETS LightDM-qml)
plugins/LightDM/Greeter.cpp−3
@@ -56,10 +56,7 @@ Greeter::Greeter(QObject* parent)
56 this, SLOT(showPromptFilter(QString, QLightDM::Greeter::PromptType)));
56 this, SLOT(showPromptFilter(QString, QLightDM::Greeter::PromptType)));
57 connect(d->m_greeter, SIGNAL(authenticationComplete()),
57 connect(d->m_greeter, SIGNAL(authenticationComplete()),
58 this, SLOT(authenticationCompleteFilter()));
58 this, SLOT(authenticationCompleteFilter()));
59− connect(d->m_greeter, SIGNAL(idle()), this, SIGNAL(idle()));
60− connect(d->m_greeter, SIGNAL(reset()), this, SIGNAL(reset()));
61
59
62− d->m_greeter->setResettable(true);
63 d->m_greeter->connectSync();
60 d->m_greeter->connectSync();
64}
61}
65
62
plugins/LightDM/Greeter.h−2
@@ -56,8 +56,6 @@ Q_SIGNALS:
56 void authenticationComplete();
56 void authenticationComplete();
57 void authenticationUserChanged(const QString &user);
57 void authenticationUserChanged(const QString &user);
58 void promptlessChanged();
58 void promptlessChanged();
59− void idle();
60− void reset();
61
59
62 // This signal is emitted by external agents like indicators, and the UI
60 // This signal is emitted by external agents like indicators, and the UI
63 // should switch to this user if possible.
61 // should switch to this user if possible.
plugins/LightDM/URLDispatcher.cppdeleted−55
@@ -1,55 +0,0 @@
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.hdeleted−34
@@ -1,34 +0,0 @@
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,7 +20,6 @@
20#include "plugin.h"
20#include "plugin.h"
21#include "DBusGreeterList.h"
21#include "DBusGreeterList.h"
22#include "Greeter.h"
22#include "Greeter.h"
23−#include "URLDispatcher.h"
24#include "UsersModel.h"
23#include "UsersModel.h"
25#include <libusermetricsoutput/ColorTheme.h>
24#include <libusermetricsoutput/ColorTheme.h>
26#include <libusermetricsoutput/UserMetrics.h>
25#include <libusermetricsoutput/UserMetrics.h>
@@ -47,13 +46,6 @@ static QObject *greeter_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
47 return greeter;
46 return greeter;
48}
47}
49
48
50−static QObject *dispatcher_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
51−{
52− Q_UNUSED(engine)
53− Q_UNUSED(scriptEngine)
54− return new URLDispatcher();
55−}
56−
57static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
49static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
58{
50{
59 Q_UNUSED(engine)
51 Q_UNUSED(engine)
@@ -75,7 +67,6 @@ void LightDMPlugin::registerTypes(const char *uri)
75
67
76 Q_ASSERT(uri == QLatin1String("LightDM"));
68 Q_ASSERT(uri == QLatin1String("LightDM"));
77 qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider);
69 qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider);
78− qmlRegisterSingletonType<URLDispatcher>(uri, 0, 1, "URLDispatcher", dispatcher_provider);
79 qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider);
70 qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider);
80 qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable");
71 qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable");
81 qmlRegisterSingletonType<UserMetricsOutput::UserMetrics>(uri, 0, 1, "Infographic", infographic_provider);
72 qmlRegisterSingletonType<UserMetricsOutput::UserMetrics>(uri, 0, 1, "Infographic", infographic_provider);
plugins/SessionBroadcast/SessionBroadcast.cpp−35
@@ -18,26 +18,11 @@
18
18
19#include "SessionBroadcast.h"
19#include "SessionBroadcast.h"
20#include <QDBusConnection>
20#include <QDBusConnection>
21−#include <QDBusConnectionInterface>
22−#include <QDBusInterface>
23
21
24SessionBroadcast::SessionBroadcast(QObject* parent)
22SessionBroadcast::SessionBroadcast(QObject* parent)
25 : QObject(parent)
23 : QObject(parent)
26{
24{
27 auto connection = QDBusConnection::SM_BUSNAME();
25 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 &)));
41
26
42 connection.connect("com.canonical.Unity.Greeter.Broadcast",
27 connection.connect("com.canonical.Unity.Greeter.Broadcast",
43 "/com/canonical/Unity/Greeter/Broadcast",
28 "/com/canonical/Unity/Greeter/Broadcast",
@@ -47,26 +32,6 @@ SessionBroadcast::SessionBroadcast(QObject* parent)
47 SLOT(onShowHome(const QString &)));
32 SLOT(onShowHome(const QString &)));
48}
33}
49
34
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−
70void SessionBroadcast::onShowHome(const QString &username)
35void SessionBroadcast::onShowHome(const QString &username)
71{
36{
72 // Only listen to requests meant for us
37 // Only listen to requests meant for us
plugins/SessionBroadcast/SessionBroadcast.h−11
@@ -31,22 +31,11 @@ class SessionBroadcast: public QObject
31public:
31public:
32 explicit SessionBroadcast(QObject *parent = 0);
32 explicit SessionBroadcast(QObject *parent = 0);
33
33
34− Q_INVOKABLE void requestUrlStart(const QString &username, const QString &url);
35− Q_INVOKABLE void requestHomeShown(const QString &username);
36−
37Q_SIGNALS:
34Q_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);
42 void showHome();
35 void showHome();
43
36
44private Q_SLOTS:
37private Q_SLOTS:
45− void onStartUrl(const QString &username, const QString &url);
46 void onShowHome(const QString &username);
38 void onShowHome(const QString &username);
47−
48−private:
49− QDBusInterface *m_broadcaster;
50};
39};
51
40
52#endif
41#endif
plugins/SessionManager/CMakeLists.txtdeleted−22
@@ -1,22 +0,0 @@
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.cppdeleted−124
@@ -1,124 +0,0 @@
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.hdeleted−61
@@ -1,61 +0,0 @@
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.cppdeleted−35
@@ -1,35 +0,0 @@
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.hdeleted−35
@@ -1,35 +0,0 @@
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/qmldirdeleted−2
@@ -1,2 +0,0 @@
1−module SessionManager
2−plugin SessionManager-qml
plugins/Unity/Launcher/backend/launcherbackend.cpp+2−16
@@ -37,15 +37,12 @@ public:
37 bool countVisible;
37 bool countVisible;
38};
38};
39
39
40−LauncherBackend::LauncherBackend(bool greeterMode, QObject *parent):
40+LauncherBackend::LauncherBackend(QObject *parent):
41 QDBusVirtualObject(parent),
41 QDBusVirtualObject(parent),
42− m_greeterMode(greeterMode),
43 m_accounts(nullptr)
42 m_accounts(nullptr)
44{
43{
45#ifndef LAUNCHER_TESTING
44#ifndef LAUNCHER_TESTING
46 m_accounts = new AccountsServiceDBusAdaptor(this);
45 m_accounts = new AccountsServiceDBusAdaptor(this);
47− connect(m_accounts, SIGNAL(propertiesChanged(QString, QString, QStringList)),
48− this, SLOT(accountsListChanged(QString, QString, QStringList)));
49#endif
46#endif
50 m_user = qgetenv("USER");
47 m_user = qgetenv("USER");
51 syncFromAccounts();
48 syncFromAccounts();
@@ -228,7 +225,7 @@ void LauncherBackend::setCountVisible(const QString &appId, bool visible) const
228
225
229void LauncherBackend::setUser(const QString &username)
226void LauncherBackend::setUser(const QString &username)
230{
227{
231− if (m_greeterMode && m_user != username) {
228+ if (qgetenv("USER") == "lightdm" && m_user != username) {
232 m_user = username;
229 m_user = username;
233 syncFromAccounts();
230 syncFromAccounts();
234 }
231 }
@@ -241,15 +238,6 @@ void LauncherBackend::triggerQuickListAction(const QString &appId, const QString
241 Q_UNUSED(quickListId)
238 Q_UNUSED(quickListId)
242}
239}
243
240
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−
253void LauncherBackend::syncFromAccounts()
241void LauncherBackend::syncFromAccounts()
254{
242{
255 QList<QVariantMap> apps;
243 QList<QVariantMap> apps;
@@ -311,8 +299,6 @@ void LauncherBackend::syncFromAccounts()
311 loadFromVariant(app.toMap());
299 loadFromVariant(app.toMap());
312 }
300 }
313 }
301 }
314−
315− Q_EMIT refreshApplications();
316}
302}
317
303
318void LauncherBackend::syncToAccounts()
304void LauncherBackend::syncToAccounts()
plugins/Unity/Launcher/backend/launcherbackend.h+1−7
@@ -42,7 +42,7 @@ class LauncherBackend : public QDBusVirtualObject
42 friend LauncherBackendTest;
42 friend LauncherBackendTest;
43
43
44public:
44public:
45− LauncherBackend(bool greeterMode = false, QObject *parent = 0);
45+ LauncherBackend(QObject *parent = 0);
46 virtual ~LauncherBackend();
46 virtual ~LauncherBackend();
47
47
48 /**
48 /**
@@ -162,7 +162,6 @@ public:
162 virtual QString introspect (const QString &path) const;
162 virtual QString introspect (const QString &path) const;
163
163
164Q_SIGNALS:
164Q_SIGNALS:
165− void refreshApplications() const;
166 void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList) const;
165 void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList) const;
167 void progressChanged(const QString &appId, int progress) const;
166 void progressChanged(const QString &appId, int progress) const;
168 void countChanged(const QString &appId, int count) const;
167 void countChanged(const QString &appId, int count) const;
@@ -179,8 +178,6 @@ private:
179 void syncFromAccounts();
178 void syncFromAccounts();
180 void syncToAccounts();
179 void syncToAccounts();
181
180
182− bool m_greeterMode;
183−
184 QList<QString> m_storedApps;
181 QList<QString> m_storedApps;
185 mutable QHash<QString, LauncherBackendItem*> m_itemCache;
182 mutable QHash<QString, LauncherBackendItem*> m_itemCache;
186
183
@@ -189,9 +186,6 @@ private:
189
186
190 void emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const;
187 void emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const;
191
188
192−private Q_SLOTS:
193− void accountsListChanged(const QString &user, const QString &interface, const QStringList &changed);
194−
195protected: /* Protected to allow testing */
189protected: /* Protected to allow testing */
196 LauncherBackendItem* getItem(const QString& appId) const;
190 LauncherBackendItem* getItem(const QString& appId) const;
197
191
plugins/Unity/Launcher/launcheritem.cpp+9−14
@@ -22,13 +22,12 @@
22
22
23#include <libintl.h>
23#include <libintl.h>
24
24
25−LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, bool pinnable, QObject *parent) :
25+LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
26 LauncherItemInterface(parent),
26 LauncherItemInterface(parent),
27 m_appId(appId),
27 m_appId(appId),
28 m_name(name),
28 m_name(name),
29 m_icon(icon),
29 m_icon(icon),
30 m_pinned(false),
30 m_pinned(false),
31− m_pinnable(pinnable),
32 m_running(false),
31 m_running(false),
33 m_recent(false),
32 m_recent(false),
34 m_progress(-1),
33 m_progress(-1),
@@ -39,12 +38,10 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
39 QuickListEntry nameAction;
38 QuickListEntry nameAction;
40 nameAction.setText(m_name);
39 nameAction.setText(m_name);
41 m_quickList->appendAction(nameAction);
40 m_quickList->appendAction(nameAction);
42− if (m_pinnable) {
43− QuickListEntry pinningAction;
41+ QuickListEntry pinningAction;
44− pinningAction.setActionId("pin_item");
42+ pinningAction.setActionId("pin_item");
45− pinningAction.setText(gettext("Lock to Launcher"));
43+ pinningAction.setText(gettext("Lock to Launcher"));
46− m_quickList->appendAction(pinningAction);
44+ m_quickList->appendAction(pinningAction);
47− }
48}
45}
49
46
50QString LauncherItem::appId() const
47QString LauncherItem::appId() const
@@ -71,12 +68,10 @@ void LauncherItem::setPinned(bool pinned)
71{
68{
72 if (m_pinned != pinned) {
69 if (m_pinned != pinned) {
73 m_pinned = pinned;
70 m_pinned = pinned;
74− if (m_pinnable) {
75− QuickListEntry entry;
71+ QuickListEntry entry;
76− entry.setActionId("pin_item");
72+ entry.setActionId("pin_item");
77− entry.setText(pinned ? gettext("Unlock from Launcher") : gettext("Lock to Launcher"));
73+ entry.setText(pinned ? gettext("Unlock from Launcher") : gettext("Lock to Launcher"));
78− m_quickList->updateAction(entry);
74+ m_quickList->updateAction(entry);
79− }
80 Q_EMIT pinnedChanged(pinned);
75 Q_EMIT pinnedChanged(pinned);
81 }
76 }
82}
77}
plugins/Unity/Launcher/launcheritem.h+1−2
@@ -32,7 +32,7 @@ class LauncherItem: public LauncherItemInterface
32{
32{
33 Q_OBJECT
33 Q_OBJECT
34public:
34public:
35− LauncherItem(const QString &appId, const QString &name, const QString &icon, bool pinnable, QObject *parent = 0);
35+ LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0);
36
36
37 QString appId() const;
37 QString appId() const;
38 QString name() const;
38 QString name() const;
@@ -67,7 +67,6 @@ private:
67 QString m_name;
67 QString m_name;
68 QString m_icon;
68 QString m_icon;
69 bool m_pinned;
69 bool m_pinned;
70− bool m_pinnable;
71 bool m_running;
70 bool m_running;
72 bool m_recent;
71 bool m_recent;
73 int m_progress;
72 int m_progress;
plugins/Unity/Launcher/launchermodel.cpp+11−41
@@ -29,15 +29,20 @@ using namespace unity::shell::application;
29
29
30LauncherModel::LauncherModel(QObject *parent):
30LauncherModel::LauncherModel(QObject *parent):
31 LauncherModelInterface(parent),
31 LauncherModelInterface(parent),
32− m_greeterMode(qgetenv("XDG_SESSION_CLASS") == "greeter"),
33− m_backend(new LauncherBackend(m_greeterMode, this)),
32+ m_backend(new LauncherBackend(this)),
34 m_appManager(0)
33 m_appManager(0)
35{
34{
36 connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
35 connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
37 connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
36 connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
38− connect(m_backend, SIGNAL(refreshApplications()), SLOT(refreshStoredApplications()));
39
37
40− refreshStoredApplications();
38+ Q_FOREACH (const QString &entry, m_backend->storedApplications()) {
39+ LauncherItem *item = new LauncherItem(entry,
40+ m_backend->displayName(entry),
41+ m_backend->icon(entry),
42+ this);
43+ item->setPinned(true);
44+ m_list.append(item);
45+ }
41}
46}
42
47
43LauncherModel::~LauncherModel()
48LauncherModel::~LauncherModel()
@@ -136,8 +141,7 @@ void LauncherModel::pin(const QString &appId, int index)
136 beginInsertRows(QModelIndex(), index, index);
141 beginInsertRows(QModelIndex(), index, index);
137 LauncherItem *item = new LauncherItem(appId,
142 LauncherItem *item = new LauncherItem(appId,
138 m_backend->displayName(appId),
143 m_backend->displayName(appId),
139− m_backend->icon(appId),
144+ m_backend->icon(appId));
140− !m_greeterMode);
141 item->setPinned(true);
145 item->setPinned(true);
142 m_list.insert(index, item);
146 m_list.insert(index, item);
143 endInsertRows();
147 endInsertRows();
@@ -213,40 +217,6 @@ QString LauncherModel::getUrlForAppId(const QString &appId) const
213 return "appid://" + package + "/" + app + "/current-user-version";
217 return "appid://" + package + "/" + app + "/current-user-version";
214}
218}
215
219
216−void LauncherModel::refreshStoredApplications()
217−{
218− // First remove any existing ones
219− QList<int> storedAppIndices;
220− for (int i = 0; i < m_list.count(); ++i) {
221− if (!m_list.at(i)->recent()) {
222− storedAppIndices << i;
223− }
224− }
225− int run = 0;
226− while (storedAppIndices.count() > 0) {
227− beginRemoveRows(QModelIndex(), storedAppIndices.first() - run, storedAppIndices.first() - run);
228− m_list.takeAt(storedAppIndices.first() - run)->deleteLater();
229− endRemoveRows();
230− storedAppIndices.takeFirst();
231− ++run;
232− }
233−
234− // Now insert all stored apps at beginning of list
235− QStringList storedApplications = m_backend->storedApplications();
236− beginInsertRows(QModelIndex(), 0, storedApplications.size() - 1);
237− run = 0;
238− Q_FOREACH (const QString &entry, storedApplications) {
239− LauncherItem *item = new LauncherItem(entry,
240− m_backend->displayName(entry),
241− m_backend->icon(entry),
242− !m_greeterMode,
243− this);
244− item->setPinned(true);
245− m_list.insert(run++, item);
246− }
247− endInsertRows();
248−}
249−
250ApplicationManagerInterface *LauncherModel::applicationManager() const
220ApplicationManagerInterface *LauncherModel::applicationManager() const
251{
221{
252 return m_appManager;
222 return m_appManager;
@@ -354,7 +324,7 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
354 if (found) {
324 if (found) {
355 // Shall we paint some running/recent app highlight? If yes, do it here.
325 // Shall we paint some running/recent app highlight? If yes, do it here.
356 } else {
326 } else {
357− LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), !m_greeterMode);
327+ LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString());
358 item->setRecent(true);
328 item->setRecent(true);
359 item->setFocused(app->focused());
329 item->setFocused(app->focused());
360
330
plugins/Unity/Launcher/launchermodel.h−2
@@ -63,7 +63,6 @@ private:
63private Q_SLOTS:
63private Q_SLOTS:
64 void progressChanged(const QString &appId, int progress);
64 void progressChanged(const QString &appId, int progress);
65 void countChanged(const QString &appId, int count);
65 void countChanged(const QString &appId, int count);
66− void refreshStoredApplications();
67
66
68 void applicationAdded(const QModelIndex &parent, int row);
67 void applicationAdded(const QModelIndex &parent, int row);
69 void applicationRemoved(const QModelIndex &parent, int row);
68 void applicationRemoved(const QModelIndex &parent, int row);
@@ -71,7 +70,6 @@ private Q_SLOTS:
71
70
72private:
71private:
73 QList<LauncherItem*> m_list;
72 QList<LauncherItem*> m_list;
74− bool m_greeterMode;
75 LauncherBackend *m_backend;
73 LauncherBackend *m_backend;
76 ApplicationManagerInterface *m_appManager;
74 ApplicationManagerInterface *m_appManager;
77};
75};
qml/Components/BasicShell.qmldeleted−84
@@ -1,84 +0,0 @@
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+53−1
@@ -15,11 +15,13 @@
15 */
15 */
16
16
17import AccountsService 0.1
17import AccountsService 0.1
18+import LightDM 0.1 as LightDM
18import QtQuick 2.0
19import QtQuick 2.0
19
20
20Item {
21Item {
21 id: demo
22 id: demo
22
23
24+ property Item greeter
23 property Item dash
25 property Item dash
24 property Item launcher
26 property Item launcher
25 property Item indicators
27 property Item indicators
@@ -34,6 +36,7 @@ Item {
34 property bool paused: false
36 property bool paused: false
35
37
36 onPausedChanged: {
38 onPausedChanged: {
39+ if (d.rightEdgeDemo) d.rightEdgeDemo.paused = paused
37 if (d.topEdgeDemo) d.topEdgeDemo.paused = paused
40 if (d.topEdgeDemo) d.topEdgeDemo.paused = paused
38 if (d.bottomEdgeDemo) d.bottomEdgeDemo.paused = paused
41 if (d.bottomEdgeDemo) d.bottomEdgeDemo.paused = paused
39 if (d.leftEdgeDemo) d.leftEdgeDemo.paused = paused
42 if (d.leftEdgeDemo) d.leftEdgeDemo.paused = paused
@@ -42,6 +45,16 @@ Item {
42
45
43 function hideEdgeDemoInShell() {
46 function hideEdgeDemoInShell() {
44 AccountsService.demoEdges = false;
47 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();
45 }
58 }
46
59
47 function stopDemo() {
60 function stopDemo() {
@@ -49,6 +62,7 @@ Item {
49 dashEnabled = true
62 dashEnabled = true
50 panelEnabled = true
63 panelEnabled = true
51 panelContentEnabled = true
64 panelContentEnabled = true
65+ if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
52 if (d.topEdgeDemo) d.topEdgeDemo.destroy()
66 if (d.topEdgeDemo) d.topEdgeDemo.destroy()
53 if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy()
67 if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy()
54 if (d.leftEdgeDemo) d.leftEdgeDemo.destroy()
68 if (d.leftEdgeDemo) d.leftEdgeDemo.destroy()
@@ -65,17 +79,24 @@ Item {
65 panelEnabled = false;
79 panelEnabled = false;
66 panelContentEnabled = false;
80 panelContentEnabled = false;
67
81
82+ // Begin with either greeter or dash, depending on which is visible
83+ if (greeter && greeter.shown) {
84+ startRightEdgeDemo()
85+ } else {
68− startTopEdgeDemo()
86+ startTopEdgeDemo()
87+ }
69 }
88 }
70
89
71 QtObject {
90 QtObject {
72 id: d
91 id: d
73 property Component overlay
92 property Component overlay
93+ property QtObject rightEdgeDemo
74 property QtObject topEdgeDemo
94 property QtObject topEdgeDemo
75 property QtObject bottomEdgeDemo
95 property QtObject bottomEdgeDemo
76 property QtObject leftEdgeDemo
96 property QtObject leftEdgeDemo
77 property QtObject finalEdgeDemo
97 property QtObject finalEdgeDemo
78 property bool showEdgeDemo: AccountsService.demoEdges
98 property bool showEdgeDemo: AccountsService.demoEdges
99+ property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user
79
100
80 onShowEdgeDemoChanged: {
101 onShowEdgeDemoChanged: {
81 stopDemo()
102 stopDemo()
@@ -85,6 +106,37 @@ Item {
85 }
106 }
86 }
107 }
87
108
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+
88 function startTopEdgeDemo() {
140 function startTopEdgeDemo() {
89 demo.panelEnabled = true;
141 demo.panelEnabled = true;
90 if (demo.dash && demo.underlay) {
142 if (demo.dash && demo.underlay) {
qml/Components/Lockscreen.qml+19
@@ -48,6 +48,8 @@ Showable {
48 property int minPinLength: -1
48 property int minPinLength: -1
49 property int maxPinLength: -1
49 property int maxPinLength: -1
50
50
51+ property url background: ""
52+
51 signal entered(string passphrase)
53 signal entered(string passphrase)
52 signal cancel()
54 signal cancel()
53 signal emergencyCall()
55 signal emergencyCall()
@@ -73,6 +75,23 @@ Showable {
73 PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
75 PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
74 }
76 }
75
77
78+ Rectangle {
79+ // In case background fails to load or is undefined
80+ id: backgroundBackup
81+ anchors.fill: parent
82+ color: "black"
83+ }
84+
85+ Image {
86+ id: backgroundImage
87+ objectName: "lockscreenBackground"
88+ anchors {
89+ fill: parent
90+ }
91+ source: root.required ? root.background : ""
92+ fillMode: Image.PreserveAspectCrop
93+ }
94+
76 MouseArea {
95 MouseArea {
77 anchors.fill: root
96 anchors.fill: root
78 }
97 }
qml/Components/PageHeader.qml+2−3
@@ -18,7 +18,6 @@ import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Ubuntu.Components.Popups 0.1
19import Ubuntu.Components.Popups 0.1
20import Ubuntu.Components.ListItems 0.1 as ListItem
20import Ubuntu.Components.ListItems 0.1 as ListItem
21−import SessionManager 0.1
22import Unity 0.2
21import Unity 0.2
23
22
24Item {
23Item {
@@ -52,8 +51,8 @@ Item {
52 }
51 }
53
52
54 Connections {
53 Connections {
55− target: SessionManager
54+ target: greeter
56− onActiveChanged: if (!SessionManager.active) resetSearch()
55+ onShownChanged: if (shown) resetSearch()
57 }
56 }
58
57
59 Flickable {
58 Flickable {
qml/Dash/ScopeListView.qml+2−3
@@ -16,14 +16,13 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Dash 0.1
18import Dash 0.1
19−import SessionManager 0.1
20
19
21ListViewWithPageHeader {
20ListViewWithPageHeader {
22 maximumFlickVelocity: height * 10
21 maximumFlickVelocity: height * 10
23 flickDeceleration: height * 2
22 flickDeceleration: height * 2
24
23
25 Connections {
24 Connections {
26− target: SessionManager
25+ target: greeter
27− onActiveChanged: if (!SessionManager.active) showHeader()
26+ onShownChanged: if (greeter.shown) showHeader()
28 }
27 }
29}
28}
qml/Greeter/Clock.qml+1−1
@@ -39,7 +39,7 @@ Item {
39
39
40 busName: "com.canonical.indicator.datetime"
40 busName: "com.canonical.indicator.datetime"
41 actionsObjectPath: "/com/canonical/indicator/datetime"
41 actionsObjectPath: "/com/canonical/indicator/datetime"
42− menuObjectPath: clock.visible ? "/com/canonical/indicator/datetime/phone_greeter" : ""
42+ menuObjectPath: clock.visible ? "/com/canonical/indicator/datetime/phone" : ""
43
43
44 Indicators.RootActionState {
44 Indicators.RootActionState {
45 menu: timeModel.model
45 menu: timeModel.model
qml/Greeter/Greeter.qml+3−36
@@ -23,9 +23,9 @@ import "../Components"
23Showable {
23Showable {
24 id: greeter
24 id: greeter
25 enabled: shown
25 enabled: shown
26− created: greeterContentLoader.status == Loader.Ready
26+ created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
27
27
28− property url background
28+ property url defaultBackground
29
29
30 // 1 when fully shown and 0 when fully hidden
30 // 1 when fully shown and 0 when fully hidden
31 property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
31 property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
@@ -118,36 +118,6 @@ Showable {
118 }
118 }
119 }
119 }
120
120
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−
151 Loader {
121 Loader {
152 id: greeterContentLoader
122 id: greeterContentLoader
153 objectName: "greeterContentLoader"
123 objectName: "greeterContentLoader"
@@ -155,6 +125,7 @@ Showable {
155 property var model: LightDM.Users
125 property var model: LightDM.Users
156 property int currentIndex: 0
126 property int currentIndex: 0
157 property var infographicModel: LightDM.Infographic
127 property var infographicModel: LightDM.Infographic
128+ readonly property int backgroundTopMargin: -greeter.y
158
129
159 source: required ? "GreeterContent.qml" : ""
130 source: required ? "GreeterContent.qml" : ""
160
131
@@ -174,10 +145,6 @@ Showable {
174 }
145 }
175
146
176 onTease: showLabelAnimation.start()
147 onTease: showLabelAnimation.start()
177− onShownChanged: {
178− showLabelAnimation.stop()
179− swipeHint.opacity = 0
180− }
181
148
182 Label {
149 Label {
183 id: swipeHint
150 id: swipeHint
qml/Greeter/GreeterContent.qml+38
@@ -24,9 +24,46 @@ Item {
24 id: root
24 id: root
25 anchors.fill: parent
25 anchors.fill: parent
26
26
27+ property bool ready: background.source == "" || background.status == Image.Ready || background.status == Image.Error
28+
27 signal selected(int uid)
29 signal selected(int uid)
28 signal unlocked(int uid)
30 signal unlocked(int uid)
29
31
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+
30 Rectangle {
67 Rectangle {
31 anchors.fill: parent
68 anchors.fill: parent
32 color: "black"
69 color: "black"
@@ -108,6 +145,7 @@ Item {
108
145
109 Clock {
146 Clock {
110 id: clock
147 id: clock
148+ visible: narrowMode
111
149
112 anchors {
150 anchors {
113 top: parent.top
151 top: parent.top
qml/Greeter/GreeterEdgeDemo.qmldeleted−102
@@ -1,102 +0,0 @@
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,6 +59,8 @@ Item {
59
59
60 visible: model.label !== ""
60 visible: model.label !== ""
61
61
62+ Component.onCompleted: startShowAnimation()
63+
62 Item {
64 Item {
63 id: dataCircle
65 id: dataCircle
64 objectName: "dataCircle"
66 objectName: "dataCircle"
qml/GreeterShell.qmldeleted−283
@@ -1,283 +0,0 @@
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(LauncherModel.getUrlForAppId(appId))
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+4−1
@@ -227,7 +227,10 @@ Item {
227 width: parent.width
227 width: parent.width
228
228
229 onYChanged: {
229 onYChanged: {
230+ if (greeter.shown) {
231+ showAnimation.duration = 0
232+ hideAnimation.duration = 0
230− if (!showAnimation.running && !hideAnimation.running) {
233+ } else if (!showAnimation.running && !hideAnimation.running) {
231 if (parent.height > 0) {
234 if (parent.height > 0) {
232 showAnimation.duration = Math.min(showableAnimationDuration * (1 - (parent.height - y) / parent.height), showableAnimationDuration)
235 showAnimation.duration = Math.min(showableAnimationDuration * (1 - (parent.height - y) / parent.height), showableAnimationDuration)
233 hideAnimation.duration = showableAnimationDuration - showAnimation.duration
236 hideAnimation.duration = showableAnimationDuration - showAnimation.duration
qml/Notifications/NotificationMenuItemFactory.qml+9−26
@@ -97,36 +97,19 @@ Loader {
97 Component {
97 Component {
98 id: pinLock
98 id: pinLock
99
99
100− Item {
100+ Lockscreen {
101+ anchors.left: parent.left; anchors.right: parent.right
101 height: menuFactory.maxHeight
102 height: menuFactory.maxHeight
102− anchors.left: parent.left
103+ placeholderText: i18n.tr("Please enter SIM PIN")
103− anchors.right: parent.right
104+ background: shell.background
104−
105− Rectangle {
106− // In case background fails to load or is undefined
107− anchors.fill: parent
108− color: "black"
109− }
110
105
111− Image {
106+ onEntered: {
112− objectName: "lockscreenBackground"
107+ menuModel.changeState(menuIndex, passphrase);
113− anchors.fill: parent
108+ entryEnabled = false;
114− source: shell.background
115− fillMode: Image.PreserveAspectCrop
116 }
109 }
117
110
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: {
111+ onCancel: {
128− menuModel.activate(menuIndex, false);
112+ menuModel.activate(menuIndex, false);
129− }
130 }
113 }
131 }
114 }
132 }
115 }
qml/Shell.qml+177−31
@@ -21,19 +21,28 @@ import Unity.Application 0.1
21import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
22import Ubuntu.Gestures 0.1
22import Ubuntu.Gestures 0.1
23import Unity.Launcher 0.1
23import Unity.Launcher 0.1
24+import LightDM 0.1 as LightDM
24import Powerd 0.1
25import Powerd 0.1
25import SessionBroadcast 0.1
26import SessionBroadcast 0.1
26−import SessionManager 0.1
27import "Dash"
27import "Dash"
28+import "Greeter"
28import "Launcher"
29import "Launcher"
29import "Panel"
30import "Panel"
30import "Components"
31import "Components"
31import "Notifications"
32import "Notifications"
32import Unity.Notifications 1.0 as NotificationBackend
33import Unity.Notifications 1.0 as NotificationBackend
33
34
34−BasicShell {
35+FocusScope {
35 id: shell
36 id: shell
36
37
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
37 readonly property real panelHeight: panel.panelHeight
46 readonly property real panelHeight: panel.panelHeight
38
47
39 property bool dashShown: dash.shown
48 property bool dashShown: dash.shown
@@ -69,7 +78,17 @@ BasicShell {
69 id: backgroundSettings
78 id: backgroundSettings
70 schema.id: "org.gnome.desktop.background"
79 schema.id: "org.gnome.desktop.background"
71 }
80 }
72− backgroundSource: backgroundSettings.pictureUri
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()
73
92
74 Item {
93 Item {
75 id: underlayClipper
94 id: underlayClipper
@@ -116,9 +135,10 @@ BasicShell {
116 id: dash
135 id: dash
117 objectName: "dash"
136 objectName: "dash"
118
137
138+ available: !greeter.shown && !lockscreen.shown
119 hides: [stages, launcher, panel.indicators]
139 hides: [stages, launcher, panel.indicators]
120− shown: disappearingAnimationProgress !== 1.0
140+ shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
121− enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
141+ enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
122
142
123 anchors {
143 anchors {
124 fill: parent
144 fill: parent
@@ -206,6 +226,7 @@ BasicShell {
206 shown = true;
226 shown = true;
207 panel.indicators.hide();
227 panel.indicators.hide();
208 edgeDemo.stopDemo();
228 edgeDemo.stopDemo();
229+ greeter.hide();
209 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
230 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
210 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
231 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
211 }
232 }
@@ -246,12 +267,6 @@ BasicShell {
246 }
267 }
247 }
268 }
248
269
249− Binding {
250− target: ApplicationManager
251− property: "suspended"
252− value: !SessionManager.active
253− }
254−
255 Loader {
270 Loader {
256 id: applicationsDisplayLoader
271 id: applicationsDisplayLoader
257 anchors.fill: parent
272 anchors.fill: parent
@@ -276,9 +291,132 @@ BasicShell {
276 }
291 }
277 }
292 }
278
293
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+
279 InputFilterArea {
417 InputFilterArea {
280 anchors.fill: parent
418 anchors.fill: parent
281− blockInput: ApplicationManager.focusedApplicationId.length === 0 || launcher.shown
419+ blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
282 || panel.indicators.shown
420 || panel.indicators.shown
283 }
421 }
284
422
@@ -290,7 +428,7 @@ BasicShell {
290 // We ignore any display-off signals when the proximity sensor
428 // We ignore any display-off signals when the proximity sensor
291 // is active. This usually indicates something like a phone call.
429 // is active. This usually indicates something like a phone call.
292 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
430 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
293− SessionManager.lock();
431+ greeter.showNow();
294 }
432 }
295
433
296 // No reason to chew demo CPU when user isn't watching
434 // No reason to chew demo CPU when user isn't watching
@@ -302,12 +440,17 @@ BasicShell {
302 }
440 }
303 }
441 }
304
442
305− function showHome(fromLauncher) {
443+ function showHome() {
306− var animate = fromLauncher && !stages.shown
444+ var animate = !greeter.shown && !stages.shown
445+ greeter.hide()
307 dash.setCurrentScope("clickscope", animate, false)
446 dash.setCurrentScope("clickscope", animate, false)
308 stages.hide()
447 stages.hide()
309 }
448 }
310
449
450+ function hideIndicatorMenu(delay) {
451+ panel.hideIndicatorMenu(delay);
452+ }
453+
311 Item {
454 Item {
312 id: overlay
455 id: overlay
313
456
@@ -324,8 +467,8 @@ BasicShell {
324 }
467 }
325 property string focusedAppId: ApplicationManager.focusedApplicationId
468 property string focusedAppId: ApplicationManager.focusedApplicationId
326 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
469 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
327− fullscreenMode: focusedApplication && stages.fullscreen
470+ fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown
328− searchVisible: dash.shown && dash.searchable
471+ searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
329
472
330 InputFilterArea {
473 InputFilterArea {
331 anchors {
474 anchors {
@@ -363,9 +506,8 @@ BasicShell {
363 if (edgeDemo.running)
506 if (edgeDemo.running)
364 return;
507 return;
365
508
366− showHome(true)
509+ showHome()
367 }
510 }
368−
369 onDash: {
511 onDash: {
370 if (stages.shown && !stages.overlayMode) {
512 if (stages.shown && !stages.overlayMode) {
371 if (!stages.locked) {
513 if (!stages.locked) {
@@ -373,6 +515,10 @@ BasicShell {
373 launcher.hide();
515 launcher.hide();
374 }
516 }
375 }
517 }
518+ if (greeter.shown) {
519+ greeter.hideRight();
520+ launcher.hide();
521+ }
376 }
522 }
377 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
523 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
378 onLauncherApplicationSelected: {
524 onLauncherApplicationSelected: {
@@ -389,7 +535,7 @@ BasicShell {
389 Rectangle {
535 Rectangle {
390 id: modalNotificationBackground
536 id: modalNotificationBackground
391
537
392− visible: notifications.useModal && (notifications.state == "narrow")
538+ visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
393 color: "#000000"
539 color: "#000000"
394 anchors.fill: parent
540 anchors.fill: parent
395 opacity: 0.5
541 opacity: 0.5
@@ -436,18 +582,11 @@ BasicShell {
436 blockInput: height > 0
582 blockInput: height > 0
437 }
583 }
438 }
584 }
439−
440− Connections {
441− target: SessionManager
442− onActiveChanged: {
443− if (!SessionManager.active) {
444− launcher.hide()
445− panel.indicators.hide()
446− }
447− }
448− }
449 }
585 }
450
586
587+ focus: true
588+ onFocusChanged: if (!focus) forceActiveFocus();
589+
451 InputFilterArea {
590 InputFilterArea {
452 anchors {
591 anchors {
453 top: parent.top
592 top: parent.top
@@ -468,6 +607,12 @@ BasicShell {
468 blockInput: true
607 blockInput: true
469 }
608 }
470
609
610+ Binding {
611+ target: i18n
612+ property: "domain"
613+ value: "unity8"
614+ }
615+
471 OSKController {
616 OSKController {
472 anchors.topMargin: panel.panelHeight
617 anchors.topMargin: panel.panelHeight
473 anchors.fill: parent // as needs to know the geometry of the shell
618 anchors.fill: parent // as needs to know the geometry of the shell
@@ -499,6 +644,7 @@ BasicShell {
499
644
500 EdgeDemo {
645 EdgeDemo {
501 id: edgeDemo
646 id: edgeDemo
647+ greeter: greeter
502 launcher: launcher
648 launcher: launcher
503 dash: dash
649 dash: dash
504 indicators: panel.indicators
650 indicators: panel.indicators
@@ -507,6 +653,6 @@ BasicShell {
507
653
508 Connections {
654 Connections {
509 target: SessionBroadcast
655 target: SessionBroadcast
510− onShowHome: showHome(false)
656+ onShowHome: showHome()
511 }
657 }
512}
658}
run.sh+4−6
@@ -18,14 +18,13 @@ usage() {
18 echo " -p, --pinlock Use a pin protected user." >&2
18 echo " -p, --pinlock Use a pin protected user." >&2
19 echo " -k, --keylock Use a passphrase protected user." >&2
19 echo " -k, --keylock Use a passphrase protected user." >&2
20 echo " -g, --gdb Run through gdb." >&2
20 echo " -g, --gdb Run through gdb." >&2
21− echo " -G, --greeter Run the greeter instead of the shell." >&2
22 echo " -h, --help Show this help." >&2
21 echo " -h, --help Show this help." >&2
23 echo " -m, --nomousetouch Run without -mousetouch argument." >&2
22 echo " -m, --nomousetouch Run without -mousetouch argument." >&2
24 echo >&2
23 echo >&2
25 exit 1
24 exit 1
26}
25}
27
26
28−ARGS=`getopt -n$0 -u -a --longoptions="fake,pinlock,keylock,gdb,greeter,help,nomousetouch" -o "fpkgGhm" -- "$@"`
27+ARGS=`getopt -n$0 -u -a --longoptions="fake,pinlock,keylock,gdb,help,nomousetouch" -o "fpkghm" -- "$@"`
29[ $? -ne 0 ] && usage
28[ $? -ne 0 ] && usage
30eval set -- "$ARGS"
29eval set -- "$ARGS"
31
30
@@ -36,7 +35,6 @@ do
36 -p|--pinlock) PINLOCK=true;;
35 -p|--pinlock) PINLOCK=true;;
37 -k|--keylock) KEYLOCK=true;;
36 -k|--keylock) KEYLOCK=true;;
38 -g|--gdb) GDB=true;;
37 -g|--gdb) GDB=true;;
39− -G|--greeter) QML_PHONE_SHELL_PATH=./builddir/src/unity8-greeter;;
40 -h|--help) usage;;
38 -h|--help) usage;;
41 -m|--nomousetouch) MOUSE_TOUCH=false;;
39 -m|--nomousetouch) MOUSE_TOUCH=false;;
42 --) shift;break;;
40 --) shift;break;;
@@ -46,17 +44,17 @@ done
46
44
47if $FAKE; then
45if $FAKE; then
48 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
46 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
49− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single
47+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single
50fi
48fi
51
49
52if $PINLOCK; then
50if $PINLOCK; then
53 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
51 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
54− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single-pin
52+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-pin
55fi
53fi
56
54
57if $KEYLOCK; then
55if $KEYLOCK; then
58 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
56 export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
59− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single-passphrase
57+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-passphrase
60fi
58fi
61
59
62# Force icon theme if running on the desktop, otherwise gnome theme (if running
60# Force icon theme if running on the desktop, otherwise gnome theme (if running
src/CMakeLists.txt+3−15
@@ -15,36 +15,24 @@ file(GLOB_RECURSE QML_FILES
15 ${CMAKE_SOURCE_DIR}/tests/*.svg
15 ${CMAKE_SOURCE_DIR}/tests/*.svg
16)
16)
17
17
18−set(COMMON_SRCS
18+add_executable(${SHELL_APP}
19 ApplicationArguments.h
19 ApplicationArguments.h
20 main.cpp
20 main.cpp
21 MouseTouchAdaptor.cpp
21 MouseTouchAdaptor.cpp
22 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
22 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
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− )
23+)
33
24
34qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
25qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
35−qt5_use_modules(${GREETER_APP} Gui Qml Quick Test)
36pkg_check_modules(XCB REQUIRED xcb)
26pkg_check_modules(XCB REQUIRED xcb)
37
27
38if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
28if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
39 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
29 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
40− set_target_properties(${GREETER_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
41
30
42 target_link_libraries(${SHELL_APP} ${XCB_LDFLAGS})
31 target_link_libraries(${SHELL_APP} ${XCB_LDFLAGS})
43− target_link_libraries(${GREETER_APP} ${XCB_LDFLAGS})
44endif()
32endif()
45
33
46# install binaries
34# install binaries
47−install(TARGETS ${SHELL_APP} ${GREETER_APP}
35+install(TARGETS ${SHELL_APP}
48 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
36 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
49 )
37 )
50
38
src/main.cpp+4−18
@@ -26,7 +26,6 @@
26#include <qpa/qplatformnativeinterface.h>
26#include <qpa/qplatformnativeinterface.h>
27#include <QLibrary>
27#include <QLibrary>
28#include <QDebug>
28#include <QDebug>
29−#include <QProcess>
30#include <libintl.h>
29#include <libintl.h>
31#include <dlfcn.h>
30#include <dlfcn.h>
32#include <csignal>
31#include <csignal>
@@ -43,7 +42,7 @@ int startShell(int argc, const char** argv, void* server)
43{
42{
44 const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
43 const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
45
44
46− QGuiApplication::setApplicationName(UNITY8_GREETER ? "Unity 8 Greeter" : "Unity 8");
45+ QGuiApplication::setApplicationName("Unity 8");
47 QGuiApplication *application;
46 QGuiApplication *application;
48
47
49 QCommandLineParser parser;
48 QCommandLineParser parser;
@@ -94,7 +93,7 @@ Load the testability driver");
94
93
95 QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
94 QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
96 if (indicatorProfile.isEmpty()) {
95 if (indicatorProfile.isEmpty()) {
97− indicatorProfile = UNITY8_GREETER ? "phone_greeter" : "phone";
96+ indicatorProfile = "phone";
98 }
97 }
99
98
100 resolveIconTheme();
99 resolveIconTheme();
@@ -153,7 +152,7 @@ Load the testability driver");
153 nativeInterface->setProperty("ubuntuSessionType", 1);
152 nativeInterface->setProperty("ubuntuSessionType", 1);
154 view->setProperty("role", 2); // INDICATOR_ACTOR_ROLE
153 view->setProperty("role", 2); // INDICATOR_ACTOR_ROLE
155
154
156− QUrl source(::qmlDirectory() + (UNITY8_GREETER ? "GreeterShell.qml" : "Shell.qml"));
155+ QUrl source(::qmlDirectory()+"Shell.qml");
157 prependImportPaths(view->engine(), ::overrideImportPaths());
156 prependImportPaths(view->engine(), ::overrideImportPaths());
158 if (!isUbuntuMirServer) {
157 if (!isUbuntuMirServer) {
159 prependImportPaths(view->engine(), ::nonMirImportPaths());
158 prependImportPaths(view->engine(), ::nonMirImportPaths());
@@ -161,7 +160,7 @@ Load the testability driver");
161 appendImportPaths(view->engine(), ::fallbackImportPaths());
160 appendImportPaths(view->engine(), ::fallbackImportPaths());
162
161
163 view->setSource(source);
162 view->setSource(source);
164− view->setColor(Qt::transparent);
163+ view->setColor("transparent");
165
164
166 if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || parser.isSet(fullscreenOption)) {
165 if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || parser.isSet(fullscreenOption)) {
167 view->showFullScreen();
166 view->showFullScreen();
@@ -169,19 +168,6 @@ Load the testability driver");
169 view->show();
168 view->show();
170 }
169 }
171
170
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−
185 int result = application->exec();
171 int result = application->exec();
186
172
187 delete view;
173 delete view;
tests/autopilot/unity8/application_lifecycle/tests/__init__.py+2
@@ -31,6 +31,8 @@ class ApplicationLifeCycleTestCase(tests.UnityTestCase):
31 super(ApplicationLifeCycleTestCase, self).setUp()
31 super(ApplicationLifeCycleTestCase, self).setUp()
32 self._qml_mock_enabled = False
32 self._qml_mock_enabled = False
33 self._data_dirs_mock_enabled = False
33 self._data_dirs_mock_enabled = False
34+ unity_proxy = self.launch_unity()
35+ process_helpers.unlock_unity(unity_proxy)
34
36
35 def create_test_application(self):
37 def create_test_application(self):
36 desktop_file_dict = fixture_setup.DEFAULT_DESKTOP_FILE_DICT
38 desktop_file_dict = fixture_setup.DEFAULT_DESKTOP_FILE_DICT
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+29−1
@@ -24,8 +24,11 @@ from __future__ import absolute_import
24import logging
24import logging
25import os
25import os
26
26
27+from autopilot.matchers import Eventually
27from autopilot.platform import model
28from autopilot.platform import model
29+from testtools.matchers import Equals
28
30
31+from unity8 import process_helpers
29from unity8.application_lifecycle import tests
32from unity8.application_lifecycle import tests
30
33
31
34
@@ -38,7 +41,6 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
38 if model() == 'Desktop':
41 if model() == 'Desktop':
39 self.skipTest('Test cannot be run on the desktop.')
42 self.skipTest('Test cannot be run on the desktop.')
40 super(ApplicationLifecycleTests, self).setUp()
43 super(ApplicationLifecycleTests, self).setUp()
41− self.launch_unity()
42
44
43 def swipe_screen_from_right(self):
45 def swipe_screen_from_right(self):
44 width = self.main_window.width
46 width = self.main_window.width
@@ -87,3 +89,29 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
87 self.swipe_screen_from_right()
89 self.swipe_screen_from_right()
88
90
89 self.assert_current_focused_application(application1_name)
91 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.pydeleted−75
@@ -1,75 +0,0 @@
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,7 +33,6 @@ class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
33 if platform.model() == 'Desktop':
33 if platform.model() == 'Desktop':
34 self.skipTest("URL dispatcher doesn't work on the desktop.")
34 self.skipTest("URL dispatcher doesn't work on the desktop.")
35 super(URLDispatcherTestCase, self).setUp()
35 super(URLDispatcherTestCase, self).setUp()
36− self.launch_unity()
37
36
38 def test_swipe_out_application_started_by_url_dispatcher(self):
37 def test_swipe_out_application_started_by_url_dispatcher(self):
39 _, desktop_file_path = self.create_test_application()
38 _, desktop_file_path = self.create_test_application()
tests/autopilot/unity8/indicators/tests/test_indicators.py+2
@@ -22,6 +22,7 @@ from testscenarios import multiply_scenarios
22
22
23from autopilot import platform
23from autopilot import platform
24
24
25+from unity8.process_helpers import unlock_unity
25from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26
27
27
28
@@ -34,6 +35,7 @@ class IndicatorTestCase(UnityTestCase):
34 self.skipTest('Test cannot be run on the desktop.')
35 self.skipTest('Test cannot be run on the desktop.')
35 super(IndicatorTestCase, self).setUp()
36 super(IndicatorTestCase, self).setUp()
36 self.unity_proxy = self.launch_unity()
37 self.unity_proxy = self.launch_unity()
38+ unlock_unity(self.unity_proxy)
37
39
38
40
39class IndicatorExistsTestCase(IndicatorTestCase):
41class IndicatorExistsTestCase(IndicatorTestCase):
tests/autopilot/unity8/process_helpers.py+56
@@ -40,6 +40,62 @@ class CannotAccessUnity(Exception):
40 pass
40 pass
41
41
42
42
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+
43def lock_unity(unity_proxy_obj=None):
99def lock_unity(unity_proxy_obj=None):
44 """Helper function that attempts to lock the unity greeter."""
100 """Helper function that attempts to lock the unity greeter."""
45 import evdev, time
101 import evdev, time
tests/autopilot/unity8/shell/tests/__init__.py+4−16
@@ -249,9 +249,9 @@ class UnityTestCase(AutopilotTestCase):
249 "%s=%s" % (key, value)
249 "%s=%s" % (key, value)
250 ], stderr=subprocess.STDOUT)
250 ], stderr=subprocess.STDOUT)
251
251
252− def _launch(self, executable, ready_func, **kwargs):
252+ def launch_unity(self, **kwargs):
253 """Launch the unity shell, return a proxy object for it."""
253 """Launch the unity shell, return a proxy object for it."""
254− binary_path = get_binary_path(executable)
254+ binary_path = get_binary_path()
255 lib_path = get_lib_path()
255 lib_path = get_lib_path()
256
256
257 logger.info(
257 logger.info(
@@ -293,19 +293,11 @@ class UnityTestCase(AutopilotTestCase):
293
293
294 # Ensure that the dash is visible before we return:
294 # Ensure that the dash is visible before we return:
295 logger.debug("Unity started, waiting for it to be ready.")
295 logger.debug("Unity started, waiting for it to be ready.")
296− ready_func()
296+ self.assertUnityReady()
297 logger.debug("Unity loaded and ready.")
297 logger.debug("Unity loaded and ready.")
298
298
299 return app_proxy
299 return app_proxy
300
300
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−
309 def _launch_unity_with_upstart(self, binary_path, args):
301 def _launch_unity_with_upstart(self, binary_path, args):
310 logger.info("Starting unity")
302 logger.info("Starting unity")
311 self._patch_environment("QT_LOAD_TESTABILITY", 1)
303 self._patch_environment("QT_LOAD_TESTABILITY", 1)
@@ -352,7 +344,7 @@ class UnityTestCase(AutopilotTestCase):
352 def _get_lightdm_mock_path(self, mock_type):
344 def _get_lightdm_mock_path(self, mock_type):
353 lib_path = get_mocks_library_path()
345 lib_path = get_mocks_library_path()
354 lightdm_mock_path = os.path.abspath(
346 lightdm_mock_path = os.path.abspath(
355− os.path.join(lib_path, "liblightdm", mock_type)
347+ os.path.join(lib_path, "LightDM", mock_type)
356 )
348 )
357
349
358 if not os.path.exists(lightdm_mock_path):
350 if not os.path.exists(lightdm_mock_path):
@@ -394,10 +386,6 @@ class UnityTestCase(AutopilotTestCase):
394 )
386 )
395 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
387 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
396
388
397− def assertGreeterReady(self):
398− greeter = self.main_window.get_greeter()
399− self.assertThat(greeter.created, Eventually(Equals(True)))
400−
401 def get_dash(self):
389 def get_dash(self):
402 dash = self._proxy.wait_select_single(Dash)
390 dash = self._proxy.wait_select_single(Dash)
403 return dash
391 return dash
tests/autopilot/unity8/shell/tests/disabled_test_hud.py+7−1
@@ -19,7 +19,8 @@
19
19
20from __future__ import absolute_import
20from __future__ import absolute_import
21
21
22+from unity8.process_helpers import unlock_unity
22−from unity8.shell import DragMixin
23+from unity8.shell import with_lightdm_mock, DragMixin
23from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
24from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
24
25
25from testtools.matchers import Equals
26from testtools.matchers import Equals
@@ -39,6 +40,7 @@ class TestHud(UnityTestCase, DragMixin):
39
40
40 """
41 """
41 unity_proxy = self.launch_unity()
42 unity_proxy = self.launch_unity()
43+ unlock_unity(unity_proxy)
42 hud_show_button = self.main_window.get_hud_show_button()
44 hud_show_button = self.main_window.get_hud_show_button()
43 edge_drag_area = self.main_window.get_hud_edge_drag_area()
45 edge_drag_area = self.main_window.get_hud_edge_drag_area()
44 hud = self.main_window.get_hud()
46 hud = self.main_window.get_hud()
@@ -79,6 +81,7 @@ class TestHud(UnityTestCase, DragMixin):
79
81
80 """
82 """
81 unity_proxy = self.launch_unity()
83 unity_proxy = self.launch_unity()
84+ unlock_unity(unity_proxy)
82 hud_show_button = self.main_window.get_hud_show_button()
85 hud_show_button = self.main_window.get_hud_show_button()
83 hud = self.main_window.get_hud()
86 hud = self.main_window.get_hud()
84
87
@@ -114,6 +117,7 @@ class TestHud(UnityTestCase, DragMixin):
114 def test_hide_hud_click(self):
117 def test_hide_hud_click(self):
115 """Tapping the close button of the Hud must dismiss it."""
118 """Tapping the close button of the Hud must dismiss it."""
116 unity_proxy = self.launch_unity()
119 unity_proxy = self.launch_unity()
120+ unlock_unity(unity_proxy)
117 hud = self.main_window.get_hud()
121 hud = self.main_window.get_hud()
118
122
119 self._launch_test_app_from_app_screen()
123 self._launch_test_app_from_app_screen()
@@ -130,6 +134,7 @@ class TestHud(UnityTestCase, DragMixin):
130
134
131 """
135 """
132 unity_proxy = self.launch_unity()
136 unity_proxy = self.launch_unity()
137+ unlock_unity(unity_proxy)
133 hud = self.main_window.get_hud()
138 hud = self.main_window.get_hud()
134
139
135 self._launch_test_app_from_app_screen()
140 self._launch_test_app_from_app_screen()
@@ -146,6 +151,7 @@ class TestHud(UnityTestCase, DragMixin):
146 def test_launcher_hides_hud(self):
151 def test_launcher_hides_hud(self):
147 """Opening the Launcher while the Hud is active must close the Hud."""
152 """Opening the Launcher while the Hud is active must close the Hud."""
148 unity_proxy = self.launch_unity()
153 unity_proxy = self.launch_unity()
154+ unlock_unity(unity_proxy)
149 hud = self.main_window.get_hud()
155 hud = self.main_window.get_hud()
150 launcher = self.main_window.get_launcher()
156 launcher = self.main_window.get_launcher()
151
157
tests/autopilot/unity8/shell/tests/test_emulators.py+3
@@ -34,6 +34,7 @@ except ImportError:
34
34
35from testtools.matchers import Contains, HasLength
35from testtools.matchers import Contains, HasLength
36
36
37+from unity8 import process_helpers
37from unity8.shell import emulators, fixture_setup, tests
38from unity8.shell import emulators, fixture_setup, tests
38from unity8.shell.emulators import dash as dash_emulators
39from unity8.shell.emulators import dash as dash_emulators
39
40
@@ -45,6 +46,7 @@ class MainWindowTestCase(tests.UnityTestCase):
45 def setUp(self):
46 def setUp(self):
46 super(MainWindowTestCase, self).setUp()
47 super(MainWindowTestCase, self).setUp()
47 unity_proxy = self.launch_unity()
48 unity_proxy = self.launch_unity()
49+ process_helpers.unlock_unity(unity_proxy)
48
50
49 def test_search(self):
51 def test_search(self):
50 self.main_window.search('Test')
52 self.main_window.search('Test')
@@ -60,6 +62,7 @@ class DashBaseTestCase(tests.UnityTestCase):
60 def setUp(self):
62 def setUp(self):
61 super(DashBaseTestCase, self).setUp()
63 super(DashBaseTestCase, self).setUp()
62 unity_proxy = self.launch_unity()
64 unity_proxy = self.launch_unity()
65+ process_helpers.unlock_unity(unity_proxy)
63 self.dash = self.main_window.get_dash()
66 self.dash = self.main_window.get_dash()
64
67
65
68
tests/autopilot/unity8/shell/tests/test_lock_screen.py+13−12
@@ -20,6 +20,7 @@
20
20
21from __future__ import absolute_import
21from __future__ import absolute_import
22
22
23+from unity8.process_helpers import unlock_unity
23from unity8.shell import with_lightdm_mock
24from unity8.shell import with_lightdm_mock
24from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
25from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
25
26
@@ -46,41 +47,41 @@ class TestLockscreen(UnityTestCase):
46 @with_lightdm_mock("single-pin")
47 @with_lightdm_mock("single-pin")
47 def test_can_unlock_pin_screen(self):
48 def test_can_unlock_pin_screen(self):
48 """Must be able to unlock the PIN entry lock screen."""
49 """Must be able to unlock the PIN entry lock screen."""
49− self.launch_greeter()
50+ unity_proxy = self.launch_unity()
50 greeter = self.main_window.get_greeter()
51 greeter = self.main_window.get_greeter()
51
52
52 if greeter.narrowMode:
53 if greeter.narrowMode:
53− greeter.swipe()
54+ unlock_unity(unity_proxy)
54 lockscreen = self._wait_for_lockscreen()
55 lockscreen = self._wait_for_lockscreen()
55 self._enter_pincode("1234")
56 self._enter_pincode("1234")
56 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
57 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
57 else:
58 else:
58 self._enter_prompt_passphrase("1234")
59 self._enter_prompt_passphrase("1234")
59− self.assertThat(greeter.enabled, Eventually(Equals(False)))
60+ self.assertThat(greeter.shown, Eventually(Equals(False)))
60
61
61 @with_lightdm_mock("single-passphrase")
62 @with_lightdm_mock("single-passphrase")
62 def test_can_unlock_passphrase_screen(self):
63 def test_can_unlock_passphrase_screen(self):
63 """Must be able to unlock the passphrase entry screen."""
64 """Must be able to unlock the passphrase entry screen."""
64− self.launch_greeter()
65+ unity_proxy = self.launch_unity()
65 greeter = self.main_window.get_greeter()
66 greeter = self.main_window.get_greeter()
66
67
67 if greeter.narrowMode:
68 if greeter.narrowMode:
68− greeter.swipe()
69+ unlock_unity(unity_proxy)
69 lockscreen = self._wait_for_lockscreen()
70 lockscreen = self._wait_for_lockscreen()
70 self._enter_pin_passphrase("password")
71 self._enter_pin_passphrase("password")
71 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
72 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
72 else:
73 else:
73 self._enter_prompt_passphrase("password")
74 self._enter_prompt_passphrase("password")
74− self.assertThat(greeter.enabled, Eventually(Equals(False)))
75+ self.assertThat(greeter.shown, Eventually(Equals(False)))
75
76
76 @with_lightdm_mock("single-pin")
77 @with_lightdm_mock("single-pin")
77 def test_pin_screen_wrong_code(self):
78 def test_pin_screen_wrong_code(self):
78 """Entering the wrong pin code must not dismiss the lock screen."""
79 """Entering the wrong pin code must not dismiss the lock screen."""
79− self.launch_greeter()
80+ unity_proxy = self.launch_unity()
80 greeter = self.main_window.get_greeter()
81 greeter = self.main_window.get_greeter()
81
82
82 if greeter.narrowMode:
83 if greeter.narrowMode:
83− greeter.swipe()
84+ unlock_unity(unity_proxy)
84 lockscreen = self._wait_for_lockscreen()
85 lockscreen = self._wait_for_lockscreen()
85 self._enter_pincode("4321")
86 self._enter_pincode("4321")
86 pinentryField = self.main_window.get_pinentryField()
87 pinentryField = self.main_window.get_pinentryField()
@@ -90,16 +91,16 @@ class TestLockscreen(UnityTestCase):
90 self._enter_prompt_passphrase("4231")
91 self._enter_prompt_passphrase("4231")
91 prompt = self.main_window.get_greeter().get_prompt()
92 prompt = self.main_window.get_greeter().get_prompt()
92 self.assertThat(prompt.text, Eventually(Equals("")))
93 self.assertThat(prompt.text, Eventually(Equals("")))
93− self.assertThat(greeter.enabled, Eventually(Equals(True)))
94+ self.assertThat(greeter.shown, Eventually(Equals(True)))
94
95
95 @with_lightdm_mock("single-passphrase")
96 @with_lightdm_mock("single-passphrase")
96 def test_passphrase_screen_wrong_password(self):
97 def test_passphrase_screen_wrong_password(self):
97 """Entering the wrong password must not dismiss the lock screen."""
98 """Entering the wrong password must not dismiss the lock screen."""
98− self.launch_greeter()
99+ unity_proxy = self.launch_unity()
99 greeter = self.main_window.get_greeter()
100 greeter = self.main_window.get_greeter()
100
101
101 if greeter.narrowMode:
102 if greeter.narrowMode:
102− greeter.swipe()
103+ unlock_unity(unity_proxy)
103 lockscreen = self._wait_for_lockscreen()
104 lockscreen = self._wait_for_lockscreen()
104 self._enter_pin_passphrase("foobar")
105 self._enter_pin_passphrase("foobar")
105 pinentryField = self.main_window.get_pinentryField()
106 pinentryField = self.main_window.get_pinentryField()
@@ -109,7 +110,7 @@ class TestLockscreen(UnityTestCase):
109 self._enter_prompt_passphrase("foobar")
110 self._enter_prompt_passphrase("foobar")
110 prompt = self.main_window.get_greeter().get_prompt()
111 prompt = self.main_window.get_greeter().get_prompt()
111 self.assertThat(prompt.text, Eventually(Equals("")))
112 self.assertThat(prompt.text, Eventually(Equals("")))
112− self.assertThat(greeter.enabled, Eventually(Equals(True)))
113+ self.assertThat(greeter.shown, Eventually(Equals(True)))
113
114
114 def _wait_for_lockscreen(self):
115 def _wait_for_lockscreen(self):
115 """Wait for the lock screen to load, and return it."""
116 """Wait for the lock screen to load, and return it."""
tests/autopilot/unity8/shell/tests/test_notifications.py+14−2
@@ -22,6 +22,7 @@
22from __future__ import absolute_import
22from __future__ import absolute_import
23
23
24from unity8 import shell
24from unity8 import shell
25+from unity8.process_helpers import unlock_unity
25from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26
27
27from testtools.matchers import Equals, NotEquals
28from testtools.matchers import Equals, NotEquals
@@ -124,6 +125,7 @@ class InteractiveNotificationBase(NotificationsBase):
124 def test_interactive(self):
125 def test_interactive(self):
125 """Interactive notification must react upon click on itself."""
126 """Interactive notification must react upon click on itself."""
126 unity_proxy = self.launch_unity()
127 unity_proxy = self.launch_unity()
128+ unlock_unity(unity_proxy)
127
129
128 notify_list = self._get_notifications_list()
130 notify_list = self._get_notifications_list()
129
131
@@ -162,6 +164,7 @@ class InteractiveNotificationBase(NotificationsBase):
162 """Rejecting a call should make notification expand and
164 """Rejecting a call should make notification expand and
163 offer more options."""
165 offer more options."""
164 unity_proxy = self.launch_unity()
166 unity_proxy = self.launch_unity()
167+ unlock_unity(unity_proxy)
165
168
166 summary = "Incoming call"
169 summary = "Incoming call"
167 body = "Frank Zappa\n+44 (0)7736 027340"
170 body = "Frank Zappa\n+44 (0)7736 027340"
@@ -211,6 +214,7 @@ class InteractiveNotificationBase(NotificationsBase):
211 def test_modal_sd_without_greeter (self):
214 def test_modal_sd_without_greeter (self):
212 """A snap-decision on a phone should block input to shell beneath it when there's no greeter."""
215 """A snap-decision on a phone should block input to shell beneath it when there's no greeter."""
213 unity_proxy = self.launch_unity()
216 unity_proxy = self.launch_unity()
217+ unlock_unity(unity_proxy)
214
218
215 summary = "Incoming file"
219 summary = "Incoming file"
216 body = "Frank would like to send you the file: essay.pdf"
220 body = "Frank would like to send you the file: essay.pdf"
@@ -251,7 +255,7 @@ class InteractiveNotificationBase(NotificationsBase):
251
255
252 def test_modal_sd_with_greeter (self):
256 def test_modal_sd_with_greeter (self):
253 """A snap-decision on a phone should not block input to the greeter beneath it."""
257 """A snap-decision on a phone should not block input to the greeter beneath it."""
254− unity_proxy = self.launch_greeter()
258+ unity_proxy = self.launch_unity()
255
259
256 summary = "Incoming file"
260 summary = "Incoming file"
257 body = "Frank would like to send you the file: essay.pdf"
261 body = "Frank would like to send you the file: essay.pdf"
@@ -277,8 +281,8 @@ class InteractiveNotificationBase(NotificationsBase):
277
281
278 # verify that we can swipe away the greeter (interact with the "shell")
282 # verify that we can swipe away the greeter (interact with the "shell")
279 time.sleep(1)
283 time.sleep(1)
284+ self.main_window.show_dash_swiping()
280 greeter = self.main_window.get_greeter()
285 greeter = self.main_window.get_greeter()
281− greeter.swipe()
282 self.assertThat(greeter.shown, Eventually(Equals(False)))
286 self.assertThat(greeter.shown, Eventually(Equals(False)))
283
287
284 # verify and interact with the triggered snap-decision notification
288 # verify and interact with the triggered snap-decision notification
@@ -420,6 +424,7 @@ class EphemeralNotificationsTests(NotificationsBase):
420 def test_icon_summary_body(self):
424 def test_icon_summary_body(self):
421 """Notification must display the expected summary and body text."""
425 """Notification must display the expected summary and body text."""
422 unity_proxy = self.launch_unity()
426 unity_proxy = self.launch_unity()
427+ unlock_unity(unity_proxy)
423
428
424 notify_list = self._get_notifications_list()
429 notify_list = self._get_notifications_list()
425
430
@@ -459,6 +464,7 @@ class EphemeralNotificationsTests(NotificationsBase):
459 """Notification must display the expected summary and secondary
464 """Notification must display the expected summary and secondary
460 icon."""
465 icon."""
461 unity_proxy = self.launch_unity()
466 unity_proxy = self.launch_unity()
467+ unlock_unity(unity_proxy)
462
468
463 notify_list = self._get_notifications_list()
469 notify_list = self._get_notifications_list()
464
470
@@ -495,6 +501,7 @@ class EphemeralNotificationsTests(NotificationsBase):
495 """Notifications must be displayed in order according to their
501 """Notifications must be displayed in order according to their
496 urgency."""
502 urgency."""
497 unity_proxy = self.launch_unity()
503 unity_proxy = self.launch_unity()
504+ unlock_unity(unity_proxy)
498
505
499 notify_list = self._get_notifications_list()
506 notify_list = self._get_notifications_list()
500
507
@@ -581,6 +588,7 @@ class EphemeralNotificationsTests(NotificationsBase):
581 def test_summary_and_body(self):
588 def test_summary_and_body(self):
582 """Notification must display the expected summary- and body-text."""
589 """Notification must display the expected summary- and body-text."""
583 unity_proxy = self.launch_unity()
590 unity_proxy = self.launch_unity()
591+ unlock_unity(unity_proxy)
584
592
585 notify_list = self._get_notifications_list()
593 notify_list = self._get_notifications_list()
586
594
@@ -605,6 +613,7 @@ class EphemeralNotificationsTests(NotificationsBase):
605 def test_summary_only(self):
613 def test_summary_only(self):
606 """Notification must display only the expected summary-text."""
614 """Notification must display only the expected summary-text."""
607 unity_proxy = self.launch_unity()
615 unity_proxy = self.launch_unity()
616+ unlock_unity(unity_proxy)
608
617
609 notify_list = self._get_notifications_list()
618 notify_list = self._get_notifications_list()
610
619
@@ -622,6 +631,7 @@ class EphemeralNotificationsTests(NotificationsBase):
622 """Notification must allow updating its contents while being
631 """Notification must allow updating its contents while being
623 displayed."""
632 displayed."""
624 unity_proxy = self.launch_unity()
633 unity_proxy = self.launch_unity()
634+ unlock_unity(unity_proxy)
625
635
626 notify_list = self._get_notifications_list()
636 notify_list = self._get_notifications_list()
627
637
@@ -659,6 +669,7 @@ class EphemeralNotificationsTests(NotificationsBase):
659 """Notification must allow updating its contents and layout while
669 """Notification must allow updating its contents and layout while
660 being displayed."""
670 being displayed."""
661 unity_proxy = self.launch_unity()
671 unity_proxy = self.launch_unity()
672+ unlock_unity(unity_proxy)
662
673
663 notify_list = self._get_notifications_list()
674 notify_list = self._get_notifications_list()
664
675
@@ -704,6 +715,7 @@ class EphemeralNotificationsTests(NotificationsBase):
704 def test_append_hint(self):
715 def test_append_hint(self):
705 """Notification has to accumulate body-text using append-hint."""
716 """Notification has to accumulate body-text using append-hint."""
706 unity_proxy = self.launch_unity()
717 unity_proxy = self.launch_unity()
718+ unlock_unity(unity_proxy)
707
719
708 notify_list = self._get_notifications_list()
720 notify_list = self._get_notifications_list()
709
721
tests/mocks/AccountsService/AccountsService.cpp−9
@@ -45,15 +45,6 @@ void AccountsService::setDemoEdges(bool demoEdges)
45 Q_UNUSED(demoEdges)
45 Q_UNUSED(demoEdges)
46}
46}
47
47
48−bool AccountsService::demoEdgesForCurrentUser() const
49−{
50− return false;
51−}
52−
53−void AccountsService::setDemoEdgesForCurrentUser(bool)
54−{
55−}
56−
57QString AccountsService::backgroundFile() const
48QString AccountsService::backgroundFile() const
58{
49{
59 return m_backgroundFile;
50 return m_backgroundFile;
tests/mocks/AccountsService/AccountsService.h−7
@@ -35,10 +35,6 @@ class AccountsService: public QObject
35 READ demoEdges
35 READ demoEdges
36 WRITE setDemoEdges
36 WRITE setDemoEdges
37 NOTIFY demoEdgesChanged)
37 NOTIFY demoEdgesChanged)
38− Q_PROPERTY (bool demoEdgesForCurrentUser
39− READ demoEdgesForCurrentUser
40− WRITE setDemoEdgesForCurrentUser
41− NOTIFY demoEdgesForCurrentUserChanged)
42 Q_PROPERTY (QString backgroundFile
38 Q_PROPERTY (QString backgroundFile
43 READ backgroundFile
39 READ backgroundFile
44 WRITE setBackgroundFile // only available in mock
40 WRITE setBackgroundFile // only available in mock
@@ -55,8 +51,6 @@ public:
55 void setUser(const QString &user);
51 void setUser(const QString &user);
56 bool demoEdges() const;
52 bool demoEdges() const;
57 void setDemoEdges(bool demoEdges);
53 void setDemoEdges(bool demoEdges);
58− bool demoEdgesForCurrentUser() const;
59− void setDemoEdgesForCurrentUser(bool demoEdgesForCurrentUser);
60 QString backgroundFile() const;
54 QString backgroundFile() const;
61 void setBackgroundFile(const QString &backgroundFile);
55 void setBackgroundFile(const QString &backgroundFile);
62 bool statsWelcomeScreen() const;
56 bool statsWelcomeScreen() const;
@@ -65,7 +59,6 @@ public:
65Q_SIGNALS:
59Q_SIGNALS:
66 void userChanged();
60 void userChanged();
67 void demoEdgesChanged();
61 void demoEdgesChanged();
68− void demoEdgesForCurrentUserChanged();
69 void backgroundFileChanged();
62 void backgroundFileChanged();
70 void statsWelcomeScreenChanged();
63 void statsWelcomeScreenChanged();
71
64
tests/mocks/CMakeLists.txt+1−2
@@ -31,11 +31,10 @@ endmacro()
31add_subdirectory(AccountsService)
31add_subdirectory(AccountsService)
32add_subdirectory(GSettings.1.0)
32add_subdirectory(GSettings.1.0)
33add_subdirectory(HudClient)
33add_subdirectory(HudClient)
34−add_subdirectory(liblightdm)
35add_subdirectory(libusermetrics)
34add_subdirectory(libusermetrics)
35+add_subdirectory(LightDM)
36add_subdirectory(Powerd)
36add_subdirectory(Powerd)
37add_subdirectory(QMenuModel)
37add_subdirectory(QMenuModel)
38−add_subdirectory(SessionManager)
39add_subdirectory(Ubuntu)
38add_subdirectory(Ubuntu)
40add_subdirectory(Unity)
39add_subdirectory(Unity)
41add_subdirectory(QtMultimedia)
40add_subdirectory(QtMultimedia)
tests/mocks/LightDM/CMakeLists.txtnew file+50
@@ -0,0 +1,50 @@
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/liblightdm/Greeter.cpp → tests/mocks/LightDM/Greeter.cpprenamed−11
@@ -151,23 +151,12 @@ void Greeter::setLanguage (const QString &language)
151 Q_UNUSED(language)
151 Q_UNUSED(language)
152}
152}
153
153
154−void Greeter::setResettable (bool resettable)
155−{
156− Q_UNUSED(resettable)
157−}
158−
159bool Greeter::startSessionSync(const QString &session)
154bool Greeter::startSessionSync(const QString &session)
160{
155{
161 Q_UNUSED(session)
156 Q_UNUSED(session)
162 return true;
157 return true;
163}
158}
164
159
165−QString Greeter::ensureSharedDataDirSync(const QString &username)
166−{
167− Q_UNUSED(username)
168− return "";
169−}
170−
171void Greeter::respond(const QString &response)
160void Greeter::respond(const QString &response)
172{
161{
173 Q_D(Greeter);
162 Q_D(Greeter);
tests/mocks/liblightdm/Greeter.h → tests/mocks/LightDM/Greeter.hrenamed−4
@@ -88,17 +88,13 @@ public Q_SLOTS:
88 void respond(const QString &response);
88 void respond(const QString &response);
89 void cancelAuthentication();
89 void cancelAuthentication();
90 void setLanguage (const QString &language);
90 void setLanguage (const QString &language);
91− void setResettable (bool resettable);
92 bool startSessionSync(const QString &session=QString());
91 bool startSessionSync(const QString &session=QString());
93− QString ensureSharedDataDirSync(const QString &username);
94
92
95Q_SIGNALS:
93Q_SIGNALS:
96 void showMessage(QString text, QLightDM::Greeter::MessageType type);
94 void showMessage(QString text, QLightDM::Greeter::MessageType type);
97 void showPrompt(QString text, QLightDM::Greeter::PromptType type);
95 void showPrompt(QString text, QLightDM::Greeter::PromptType type);
98 void authenticationComplete();
96 void authenticationComplete();
99 void autologinTimerExpired();
97 void autologinTimerExpired();
100− void idle();
101− void reset();
102
98
103private:
99private:
104 GreeterPrivate *d_ptr;
100 GreeterPrivate *d_ptr;
tests/mocks/liblightdm/GreeterPrivate.h → tests/mocks/LightDM/GreeterPrivate.hrenamed

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

tests/mocks/LightDM/demo/CMakeLists.txtnew file+21
@@ -0,0 +1,21 @@
1+pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
2+
3+set(LibLightDM_SOURCES
4+ ../Greeter.cpp
5+ ../UsersModel.cpp
6+ GreeterPrivate.cpp
7+ UsersModelPrivate.cpp
8+ ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
9+ )
10+
11+add_library(MockLightDM-demo STATIC ${LibLightDM_SOURCES})
12+
13+include_directories(
14+ ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
15+)
16+
17+target_link_libraries(MockLightDM-demo
18+ ${LIBUSERMETRICSOUTPUT_LDFLAGS}
19+ )
20+
21+qt5_use_modules(MockLightDM-demo Gui)
tests/mocks/LightDM/demo/GreeterPrivate.cppnew file+70
@@ -0,0 +1,70 @@
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 "../Greeter.h"
20+#include "../GreeterPrivate.h"
21+#include <QtCore/QDir>
22+#include <QtCore/QSettings>
23+
24+namespace QLightDM
25+{
26+
27+GreeterPrivate::GreeterPrivate(Greeter* parent)
28+ : authenticated(false),
29+ authenticationUser(),
30+ q_ptr(parent)
31+{
32+}
33+
34+void GreeterPrivate::handleAuthenticate()
35+{
36+ Q_Q(Greeter);
37+
38+ QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
39+ settings.beginGroup(authenticationUser);
40+ QVariant password = settings.value("password", "none");
41+
42+ if (password == "pin") {
43+ Q_EMIT q->showPrompt("PIN", Greeter::PromptTypeSecret);
44+ } else if (password == "keyboard") {
45+ Q_EMIT q->showPrompt("Password", Greeter::PromptTypeSecret);
46+ } else {
47+ authenticated = true;
48+ Q_EMIT q->authenticationComplete();
49+ }
50+}
51+
52+void GreeterPrivate::handleRespond(const QString &response)
53+{
54+ Q_Q(Greeter);
55+
56+ QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
57+ settings.beginGroup(authenticationUser);
58+ QVariant password = settings.value("password", "none");
59+
60+ QString passwordValue;
61+ if (password == "pin") {
62+ passwordValue = settings.value("passwordValue", "1234").toString();
63+ } else {
64+ passwordValue = settings.value("passwordValue", "password").toString();
65+ }
66+ authenticated = (response == passwordValue);
67+ Q_EMIT q->authenticationComplete();
68+}
69+
70+}
tests/mocks/SessionManager/SessionManager.cpp → tests/mocks/LightDM/demo/UsersModelPrivate.cpprenamed+14−16
@@ -16,28 +16,26 @@
16 * Author: Michael Terry <michael.terry@canonical.com>
16 * Author: Michael Terry <michael.terry@canonical.com>
17 */
17 */
18
18
19−#include "SessionManager.h"
19+#include "../UsersModelPrivate.h"
20
20
21−SessionManager::SessionManager(QObject* parent)
21+#include <QDir>
22− : QObject(parent),
22+#include <QSettings>
23− m_active(true)
23+#include <QStringList>
24−{
25−}
26
24
27−bool SessionManager::active() const
25+namespace QLightDM
28{
26{
29− return m_active;
30−}
31
27
32−void SessionManager::setActive(bool active)
28+UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
29+ : q_ptr(parent)
33{
30{
34− if (m_active != active) {
31+ QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
35− m_active = active;
32+ QStringList users = settings.value("users", QStringList() << "phablet").toStringList();
36− activeChanged();
33+
34+ Q_FOREACH(const QString &user, users)
35+ {
36+ QString name = settings.value(user + "/name", user[0].toUpper() + user.mid(1)).toString();
37+ entries.append({user, name, 0, 0, false, false, 0, 0});
37 }
38 }
38}
39}
39
40
40−void SessionManager::lock()
41−{
42− setActive(false);
43}
41}
tests/mocks/liblightdm/full/CMakeLists.txt → tests/mocks/LightDM/full/CMakeLists.txtrenamed+2−3
@@ -11,9 +11,8 @@ add_library(MockLightDM-full SHARED ${LibLightDM_SOURCES})
11qt5_use_modules(MockLightDM-full Gui)
11qt5_use_modules(MockLightDM-full Gui)
12
12
13set_target_properties(MockLightDM-full PROPERTIES
13set_target_properties(MockLightDM-full PROPERTIES
14− OUTPUT_NAME lightdm-qt5-3
14+ OUTPUT_NAME lightdm-qt5-2)
15− SOVERSION 0)
16
15
17install(TARGETS MockLightDM-full
16install(TARGETS MockLightDM-full
18− DESTINATION ${SHELL_INSTALL_QML}/mocks/liblightdm/full
17+ DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/full
19 )
18 )
tests/mocks/liblightdm/full/GreeterPrivate.cpp → tests/mocks/LightDM/full/GreeterPrivate.cpprenamed

The content is the same.

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

The content is the same.

tests/mocks/LightDM/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module LightDM
2+plugin MockLightDM-qml
3+typeinfo LightDM.qmltypes
tests/mocks/liblightdm/single-passphrase/CMakeLists.txt → tests/mocks/LightDM/single-passphrase/CMakeLists.txtrenamed+2−3
@@ -12,9 +12,8 @@ add_library(MockLightDM-single-passphrase SHARED ${LibLightDM_SOURCES})
12qt5_use_modules(MockLightDM-single-passphrase Gui)
12qt5_use_modules(MockLightDM-single-passphrase Gui)
13
13
14set_target_properties(MockLightDM-single-passphrase PROPERTIES
14set_target_properties(MockLightDM-single-passphrase PROPERTIES
15− OUTPUT_NAME lightdm-qt5-3
15+ OUTPUT_NAME lightdm-qt5-2)
16− SOVERSION 0)
17
16
18install(TARGETS MockLightDM-single-passphrase
17install(TARGETS MockLightDM-single-passphrase
19− DESTINATION ${SHELL_INSTALL_QML}/mocks/liblightdm/single-passphrase
18+ DESTINATION ${SHELL_INSTALL_QML}/mocks/LightDM/single-passphrase
20 )
19 )
tests/mocks/liblightdm/single-passphrase/GreeterPrivate.cpp → tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpprenamed

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

tests/mocks/SessionManager/CMakeLists.txtdeleted−19
@@ -1,19 +0,0 @@
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.hdeleted−49
@@ -1,49 +0,0 @@
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.cppdeleted−34
@@ -1,34 +0,0 @@
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.hdeleted−34
@@ -1,34 +0,0 @@
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/qmldirdeleted−2
@@ -1,2 +0,0 @@
1−module SessionManager
2−plugin MockSessionManager-qml
tests/mocks/liblightdm/CMakeLists.txtdeleted−4
@@ -1,4 +0,0 @@
1−add_subdirectory(full)
2−add_subdirectory(single)
3−add_subdirectory(single-pin)
4−add_subdirectory(single-passphrase)
tests/plugins/CMakeLists.txt+1−2
@@ -1,7 +1,6 @@
1add_subdirectory(AccountsService)
1add_subdirectory(AccountsService)
2−add_subdirectory(Dash)
3add_subdirectory(LightDM)
2add_subdirectory(LightDM)
4−add_subdirectory(SessionManager)
3+add_subdirectory(Dash)
5add_subdirectory(Ubuntu)
4add_subdirectory(Ubuntu)
6add_subdirectory(Unity)
5add_subdirectory(Unity)
7add_subdirectory(Utils)
6add_subdirectory(Utils)
tests/plugins/LightDM/CMakeLists.txt+4−5
@@ -1,6 +1,3 @@
1−include(FindPkgConfig)
2−pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-3)
3−
4add_executable(test-lightdm-dbus
1add_executable(test-lightdm-dbus
5 dbus.cpp
2 dbus.cpp
6 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
3 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
@@ -10,17 +7,19 @@ qt5_use_modules(test-lightdm-dbus Core DBus Quick Test)
10include_directories(
7include_directories(
11 ${CMAKE_CURRENT_BINARY_DIR}
8 ${CMAKE_CURRENT_BINARY_DIR}
12 ${CMAKE_SOURCE_DIR}/plugins/LightDM
9 ${CMAKE_SOURCE_DIR}/plugins/LightDM
10+ ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
13 ${LIBLIGHTDM_INCLUDE_DIRS}
11 ${LIBLIGHTDM_INCLUDE_DIRS}
14 )
12 )
15
13
16add_dependencies(test-lightdm-dbus MockLightDM-full)
14add_dependencies(test-lightdm-dbus MockLightDM-full)
17target_link_libraries(test-lightdm-dbus
15target_link_libraries(test-lightdm-dbus
18− ${LIBLIGHTDM_LDFLAGS}
16+ -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full
17+ -llightdm-qt5-2
19 )
18 )
20
19
21add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
20add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
22
21
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)
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)
24add_dependencies(testLightDMDBus test-lightdm-dbus)
23add_dependencies(testLightDMDBus test-lightdm-dbus)
25
24
26add_dependencies(qmluitests testLightDMDBus)
25add_dependencies(qmluitests testLightDMDBus)
tests/plugins/SessionManager/CMakeLists.txtdeleted−48
@@ -1,48 +0,0 @@
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.cppdeleted−38
@@ -1,38 +0,0 @@
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.hdeleted−40
@@ -1,40 +0,0 @@
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.cppdeleted−34
@@ -1,34 +0,0 @@
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.hdeleted−37
@@ -1,37 +0,0 @@
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.cppdeleted−25
@@ -1,25 +0,0 @@
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.hdeleted−39
@@ -1,39 +0,0 @@
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.cppdeleted−88
@@ -1,88 +0,0 @@
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.xmldeleted−22
@@ -1,22 +0,0 @@
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.cppdeleted−57
@@ -1,57 +0,0 @@
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+6−6
@@ -19,8 +19,8 @@ set(qmltest_DEFAULT_TARGETS qmluitests)
19set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
19set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
20set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
20set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
21
21
22−add_qml_test(. Shell)
22+add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
23−add_qml_test(. GreeterShell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/single")
23+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
24add_qml_test(Components Carousel)
24add_qml_test(Components Carousel)
25add_qml_test(Components DraggingArea)
25add_qml_test(Components DraggingArea)
26add_qml_test(Components EdgeDemoOverlay)
26add_qml_test(Components EdgeDemoOverlay)
@@ -52,10 +52,10 @@ add_qml_test(Dash/Previews PreviewTextSummary)
52add_qml_test(Dash/Previews PreviewVideoPlayback)
52add_qml_test(Dash/Previews PreviewVideoPlayback)
53add_qml_test(Dash/Previews PreviewWidgetFactory)
53add_qml_test(Dash/Previews PreviewWidgetFactory)
54add_qml_test(Dash/Previews PreviewZoomableImage)
54add_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")
55+add_qml_test(Greeter Lockscreen ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
56−add_qml_test(Greeter MultiGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
56+add_qml_test(Greeter MultiGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
57−add_qml_test(Greeter SingleGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/single")
57+add_qml_test(Greeter SingleGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
58−add_qml_test(Greeter Infographics ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
58+add_qml_test(Greeter Infographics ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
59add_qml_test(Greeter Clock ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
59add_qml_test(Greeter Clock ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
60add_qml_test(Hud Hud)
60add_qml_test(Hud Hud)
61add_qml_test(Hud Result)
61add_qml_test(Hud Result)
tests/qmltests/Greeter/tst_Lockscreen.qml+1
@@ -39,6 +39,7 @@ Rectangle {
39 minPinLength: minPinLengthTextField.text
39 minPinLength: minPinLengthTextField.text
40 maxPinLength: maxPinLengthTextField.text
40 maxPinLength: maxPinLengthTextField.text
41 username: "Lola"
41 username: "Lola"
42+ background: "../../../qml/graphics/phone_background.jpg"
42 infoText: infoTextTextField.text
43 infoText: infoTextTextField.text
43 }
44 }
44
45
tests/qmltests/Greeter/tst_SingleGreeter.qml−2
@@ -33,8 +33,6 @@ Item {
33 height: parent.height
33 height: parent.height
34 x: 0; y: 0
34 x: 0; y: 0
35
35
36− background: Qt.resolvedUrl("../../../qml/graphics/phone_background.jpg")
37−
38 property int minX: 0
36 property int minX: 0
39
37
40 onXChanged: {
38 onXChanged: {
tests/qmltests/tst_GreeterShell.qmldeleted−88
@@ -1,88 +0,0 @@
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+64−10
@@ -23,7 +23,6 @@ import GSettings 1.0
23import Unity.Application 0.1
23import Unity.Application 0.1
24import Unity.Test 0.1 as UT
24import Unity.Test 0.1 as UT
25import Powerd 0.1
25import Powerd 0.1
26−import SessionManager 0.1
27
26
28import "../../qml"
27import "../../qml"
29
28
@@ -49,7 +48,6 @@ Item {
49
48
50 Shell {
49 Shell {
51 id: shell
50 id: shell
52− defaultBackground: Qt.resolvedUrl("../../qml/graphics/phone_background.jpg")
53 }
51 }
54
52
55 UT.UnityTestCase {
53 UT.UnityTestCase {
@@ -74,6 +72,9 @@ Item {
74 ok = homeLoader !== null
72 ok = homeLoader !== null
75 && homeLoader.item !== undefined;
73 && homeLoader.item !== undefined;
76
74
75+ var greeter = findChild(shell, "greeter");
76+ ok &= greeter !== null;
77+
77 var launcherPanel = findChild(shell, "launcherPanel");
78 var launcherPanel = findChild(shell, "launcherPanel");
78 ok &= launcherPanel !== null;
79 ok &= launcherPanel !== null;
79
80
@@ -88,9 +89,17 @@ Item {
88 } while (!ok && attempts <= maxAttempts);
89 } while (!ok && attempts <= maxAttempts);
89
90
90 verify(ok);
91 verify(ok);
92+
93+ swipeAwayGreeter();
91 }
94 }
92
95
93 function cleanup() {
96 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+
94 // kill all (fake) running apps
103 // kill all (fake) running apps
95 killApps(ApplicationManager);
104 killApps(ApplicationManager);
96
105
@@ -172,6 +181,8 @@ Item {
172 }
181 }
173
182
174 function test_suspend() {
183 function test_suspend() {
184+ var greeter = findChild(shell, "greeter");
185+
175 // Launch an app from the launcher
186 // Launch an app from the launcher
176 dragLauncherIntoView();
187 dragLauncherIntoView();
177 tapOnAppIconInLauncher();
188 tapOnAppIconInLauncher();
@@ -185,27 +196,40 @@ Item {
185
196
186 // Try to suspend while proximity is engaged...
197 // Try to suspend while proximity is engaged...
187 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
198 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
188− tryCompare(SessionManager, "active", true);
199+ tryCompare(greeter, "showProgress", 0);
189
200
190 // Now really suspend
201 // Now really suspend
191 print("suspending")
202 print("suspending")
192 Powerd.displayPowerStateChange(Powerd.Off, 0);
203 Powerd.displayPowerStateChange(Powerd.Off, 0);
193 print("done suspending")
204 print("done suspending")
194− tryCompare(SessionManager, "active", false);
205+ tryCompare(greeter, "showProgress", 1);
195
206
196 tryCompare(ApplicationManager, "suspended", true);
207 tryCompare(ApplicationManager, "suspended", true);
197 compare(mainApp.state, ApplicationInfo.Suspended);
208 compare(mainApp.state, ApplicationInfo.Suspended);
198
209
199 // And wake up
210 // And wake up
200 Powerd.displayPowerStateChange(Powerd.On, 0);
211 Powerd.displayPowerStateChange(Powerd.On, 0);
212+ tryCompare(greeter, "showProgress", 1);
201
213
202− // Activate session to focus app
214+ // Swipe away greeter to focus app
203− SessionManager.active = true;
215+ swipeAwayGreeter();
204 tryCompare(ApplicationManager, "suspended", false);
216 tryCompare(ApplicationManager, "suspended", false);
205 compare(mainApp.state, ApplicationInfo.Running);
217 compare(mainApp.state, ApplicationInfo.Running);
206 tryCompare(ApplicationManager, "focusedApplicationId", mainAppId);
218 tryCompare(ApplicationManager, "focusedApplicationId", mainAppId);
207 }
219 }
208
220
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+
209 /*
233 /*
210 Perform a right-edge drag when the Dash is being show and there are
234 Perform a right-edge drag when the Dash is being show and there are
211 no running/minimized apps to be restored.
235 no running/minimized apps to be restored.
@@ -453,14 +477,22 @@ Item {
453
477
454 function test_DashShown_data() {
478 function test_DashShown_data() {
455 return [
479 return [
456− {tag: "in focus", app: false, launcher: false, indicators: false, expectedShown: true},
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},
457− {tag: "under app", app: true, launcher: false, indicators: false, expectedShown: false},
482+ {tag: "under app", greeter: false, app: true, launcher: false, indicators: false, expectedShown: false},
458− {tag: "under launcher", app: false, launcher: true, indicators: false, expectedShown: true},
483+ {tag: "under launcher", greeter: false, app: false, launcher: true, indicators: false, expectedShown: true},
459− {tag: "under indicators", app: false, launcher: false, indicators: true, expectedShown: true},
484+ {tag: "under indicators", greeter: false, app: false, launcher: false, indicators: true, expectedShown: true},
460 ]
485 ]
461 }
486 }
462
487
463 function test_DashShown(data) {
488 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+
464 if (data.app) {
496 if (data.app) {
465 dragLauncherIntoView();
497 dragLauncherIntoView();
466 tapOnAppIconInLauncher();
498 tapOnAppIconInLauncher();
@@ -490,6 +522,17 @@ Item {
490 tryCompare(searchIndicator, "opacity", 0);
522 tryCompare(searchIndicator, "opacity", 0);
491 }
523 }
492
524
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+
493 function test_searchIndicatorHideOnPreviewShown() {
536 function test_searchIndicatorHideOnPreviewShown() {
494 var searchIndicator = findChild(shell, "container");
537 var searchIndicator = findChild(shell, "container");
495 var dashContent = findChild(shell, "dashContent");
538 var dashContent = findChild(shell, "dashContent");
@@ -502,5 +545,16 @@ Item {
502
545
503 tryCompare(searchIndicator, "opacity", 0);
546 tryCompare(searchIndicator, "opacity", 0);
504 }
547 }
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+ }
505 }
559 }
506}
560}
tools/unlock-device+18−10
@@ -17,16 +17,24 @@ while getopts s:w: opt; do
17 esac
17 esac
18done
18done
19
19
20−LIGHTDM_CONFIG="
20+UNLOCK_SCRIPT='
21−[SeatDefaults]
21+import dbus, logging;
22−autologin-in-background=false
22+from unity8 import process_helpers as helpers;
23−"
23+logging.basicConfig(level=logging.INFO);
24−LIGHTDM_CONFIG_FILE="/etc/lightdm/lightdm.conf.d/99-unity8-greeter-unlock.conf"
24+bus = dbus.SystemBus().get_object("com.canonical.powerd", "/com/canonical/powerd");
25−
25+cookie = bus.requestSysState("unlock-device-hold", 1, dbus_interface="com.canonical.powerd");
26−adb shell "echo '$LIGHTDM_CONFIG' > $LIGHTDM_CONFIG_FILE"
26+helpers.restart_unity_with_testability();
27+bus.clearSysState(cookie, dbus_interface="com.canonical.powerd");
28+helpers.unlock_unity()
29+'
27
30
28eval "$WAIT_COMMAND"
31eval "$WAIT_COMMAND"
29
32
30−adb shell "rm -f $LIGHTDM_CONFIG_FILE"
33+UNLOCK_OUTPUT=$(adb shell "sudo -u phablet -i python3 -c '$UNLOCK_SCRIPT'" 2>&1)
31−
34+if echo "$UNLOCK_OUTPUT" | grep 'Greeter unlocked' >/dev/null; then
35+ echo "I: Unlock passed"
32−exit 0
36+ exit 0
37+else
38+ echo "I: Unlock failed, script output: '$UNLOCK_OUTPUT'"
39+ exit 1
40+fi