on xenial help sign in
Separate greeter from shell; use real system liblightdm; add SessionManager plugin
commit608f9335c492e9c535cda712b3124ad2b7e11d5a authorMichael Terry <michael.terry@canonical.com> dateFri 26 Jul 2013, 14:45 (13 years ago) parenta809721
74 files changed+1081−290
CMakeLists.txt+25−1 Components/BasicShell.qml+42 Components/PageHeader.qml+3−2 Greeter/Greeter.qml+2−1 GreeterShell.qml+170 Hud/Hud.qml+1−4 Shell.qml+9−152 debian/control+13 debian/copyright+1−1 debian/rules+2−5 debian/unity8-greeter.install+4 debian/unity8-greeter.postinst+12 debian/unity8-greeter.prerm+12 debian/unity8-private.install+1 debian/unity8.install−1 main.cpp+8−3 plugins/CMakeLists.txt+1 plugins/LightDM/CMakeLists.txt+5−9 plugins/SessionManager/CMakeLists.txt+27 plugins/SessionManager/SessionManager.cpp+105 plugins/SessionManager/SessionManager.h+58 plugins/SessionManager/plugin.cpp+35 plugins/SessionManager/plugin.h+35 plugins/SessionManager/qmldir+2 run+6−4 tests/autopilot/unity8/shell/tests/__init__.py+22−5 tests/autopilot/unity8/shell/tests/test_hud.py−6 tests/autopilot/unity8/shell/tests/test_lock_screen.py+4−4 tests/mocks/CMakeLists.txt+1−1 tests/mocks/LightDM/CMakeLists.txt−55 tests/mocks/liblightdm/CMakeLists.txt+4 tests/mocks/LightDM/Greeter.cpp → tests/mocks/liblightdm/Greeter.cpp tests/mocks/LightDM/Greeter.h → tests/mocks/liblightdm/Greeter.h tests/mocks/LightDM/GreeterPrivate.h → tests/mocks/liblightdm/GreeterPrivate.h tests/mocks/LightDM/QLightDM/Greeter → tests/mocks/liblightdm/QLightDM/Greeter tests/mocks/LightDM/QLightDM/InfographicModel → tests/mocks/liblightdm/QLightDM/InfographicModel tests/mocks/LightDM/QLightDM/UsersModel → tests/mocks/liblightdm/QLightDM/UsersModel tests/mocks/LightDM/UsersModel.cpp → tests/mocks/liblightdm/UsersModel.cpp tests/mocks/LightDM/UsersModel.h → tests/mocks/liblightdm/UsersModel.h tests/mocks/LightDM/UsersModelPrivate.h → tests/mocks/liblightdm/UsersModelPrivate.h tests/mocks/LightDM/demo/CMakeLists.txt → tests/mocks/liblightdm/demo/CMakeLists.txt tests/mocks/LightDM/demo/GreeterPrivate.cpp → tests/mocks/liblightdm/demo/GreeterPrivate.cpp tests/mocks/LightDM/demo/InfographicModelPrivate.cpp → tests/mocks/liblightdm/demo/InfographicModelPrivate.cpp tests/mocks/LightDM/demo/UsersModelPrivate.cpp → tests/mocks/liblightdm/demo/UsersModelPrivate.cpp tests/mocks/LightDM/full/CMakeLists.txt → tests/mocks/liblightdm/full/CMakeLists.txt+3−2 tests/mocks/LightDM/full/GreeterPrivate.cpp → tests/mocks/liblightdm/full/GreeterPrivate.cpp tests/mocks/LightDM/full/InfographicModelPrivate.cpp → tests/mocks/liblightdm/full/InfographicModelPrivate.cpp tests/mocks/LightDM/full/UsersModelPrivate.cpp → tests/mocks/liblightdm/full/UsersModelPrivate.cpp tests/mocks/LightDM/qmldir → tests/mocks/liblightdm/qmldir tests/mocks/LightDM/single-passphrase/CMakeLists.txt → tests/mocks/liblightdm/single-passphrase/CMakeLists.txt+3−2 tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpp → tests/mocks/liblightdm/single-passphrase/GreeterPrivate.cpp tests/mocks/LightDM/single-passphrase/InfographicModelPrivate.cpp → tests/mocks/liblightdm/single-passphrase/InfographicModelPrivate.cpp tests/mocks/LightDM/single-passphrase/UsersModelPrivate.cpp → tests/mocks/liblightdm/single-passphrase/UsersModelPrivate.cpp tests/mocks/LightDM/single-pin/CMakeLists.txt → tests/mocks/liblightdm/single-pin/CMakeLists.txt+3−2 tests/mocks/LightDM/single-pin/GreeterPrivate.cpp → tests/mocks/liblightdm/single-pin/GreeterPrivate.cpp tests/mocks/LightDM/single-pin/InfographicModelPrivate.cpp → tests/mocks/liblightdm/single-pin/InfographicModelPrivate.cpp tests/mocks/LightDM/single-pin/UsersModelPrivate.cpp → tests/mocks/liblightdm/single-pin/UsersModelPrivate.cpp tests/mocks/LightDM/single/CMakeLists.txt → tests/mocks/liblightdm/single/CMakeLists.txt+3−2 tests/mocks/LightDM/single/GreeterPrivate.cpp → tests/mocks/liblightdm/single/GreeterPrivate.cpp tests/mocks/LightDM/single/InfographicModelPrivate.cpp → tests/mocks/liblightdm/single/InfographicModelPrivate.cpp tests/mocks/LightDM/single/UsersModelPrivate.cpp → tests/mocks/liblightdm/single/UsersModelPrivate.cpp tests/plugins/CMakeLists.txt+1 tests/plugins/SessionManager/CMakeLists.txt+48 tests/plugins/SessionManager/LightDMSessionServer.cpp+38 tests/plugins/SessionManager/LightDMSessionServer.h+40 tests/plugins/SessionManager/LoginManagerServer.cpp+34 tests/plugins/SessionManager/LoginManagerServer.h+37 tests/plugins/SessionManager/LoginSessionServer.cpp+25 tests/plugins/SessionManager/LoginSessionServer.h+39 tests/plugins/SessionManager/client.cpp+88 tests/plugins/SessionManager/interfaces.xml+22 tests/plugins/SessionManager/server.cpp+57 tests/qmltests/CMakeLists.txt+20−28 unity8-greeter.desktop.in+10
CMakeLists.txt+25−1
@@ -95,6 +95,7 @@ declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
9595declare_autopilot_test(indicators_client unity8.indicators_client ${CMAKE_SOURCE_DIR}/tests/autopilot/)
9696
9797set(SHELL_APP unity8)
98+set(GREETER_APP unity8-greeter)
9899
99100set(shell_app_HDRS
100101 )
@@ -105,8 +106,22 @@ add_executable(${SHELL_APP}
105106 main.cpp
106107 MouseTouchAdaptor.cpp
107108 )
109+add_executable(${GREETER_APP}
110+ ${greeterapplication_MOC_SRCS}
111+ ApplicationArguments.h
112+ main.cpp
113+ MouseTouchAdaptor.cpp
114+ )
115+
116+set_target_properties(${SHELL_APP} PROPERTIES
117+ COMPILE_DEFINITIONS "APP_NAME=\"Unity 8\";QML_FILE=\"Shell.qml\""
118+ )
119+set_target_properties(${GREETER_APP} PROPERTIES
120+ COMPILE_DEFINITIONS "APP_NAME=\"Unity 8 Greeter\";QML_FILE=\"GreeterShell.qml\""
121+ )
108122
109123qt5_use_modules(${SHELL_APP} Qml Quick Test)
124+qt5_use_modules(${GREETER_APP} Qml Quick Test)
110125pkg_check_modules(XCB REQUIRED xcb)
111126
112127if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
@@ -118,9 +133,14 @@ target_link_libraries(${SHELL_APP}
118133 ${Qt5Quick_LIBRARIES}
119134 ${XCB_LDFLAGS}
120135 )
136+target_link_libraries(${GREETER_APP}
137+ ${Qt5Qml_LIBRARIES}
138+ ${Qt5Quick_LIBRARIES}
139+ ${XCB_LDFLAGS}
140+ )
121141
122142# install binaries
123−install(TARGETS ${SHELL_APP}
143+install(TARGETS ${SHELL_APP} ${GREETER_APP}
124144 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
125145 )
126146
@@ -157,11 +177,15 @@ install(DIRECTORY ${QML_DIRS}
157177
158178# generate desktop file
159179configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
180+configure_file(${GREETER_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${GREETER_APP}.desktop @ONLY)
160181
161182# install desktop file
162183install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
163184 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
164185 )
186+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GREETER_APP}.desktop
187+ DESTINATION ${CMAKE_INSTALL_DATADIR}/xgreeters
188+ )
165189
166190#
167191# Translation
Components/BasicShell.qmlnew file+42
@@ -0,0 +1,42 @@
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 "../Components"
20+import "../Components/Math.js" as MathLocal
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+ property url default_background: shell.width >= units.gu(60) ? "../graphics/tablet_background.jpg" : "../graphics/phone_background.jpg"
32+ property url background: default_background
33+
34+ VolumeControl {
35+ id: volumeControl
36+ }
37+
38+ Keys.onVolumeUpPressed: volumeControl.volumeUp()
39+ Keys.onVolumeDownPressed: volumeControl.volumeDown()
40+
41+ focus: true
42+}
Components/PageHeader.qml+3−2
@@ -18,6 +18,7 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Ubuntu.Components.Popups 0.1
2020import Ubuntu.Components.ListItems 0.1 as ListItem
21+import SessionManager 0.1
2122
2223Item {
2324 /*!
@@ -47,8 +48,8 @@ Item {
4748 }
4849
4950 Connections {
50− target: greeter
51− onShownChanged: if (shown) resetSearch()
51+ target: SessionManager
52+ onActiveChanged: if (!SessionManager.active) resetSearch()
5253 }
5354
5455 Flickable {
Greeter/Greeter.qml+2−1
@@ -34,7 +34,8 @@ Showable {
3434
3535 property alias dragHandleWidth: dragHandle.width
3636 property alias model: greeterContentLoader.model
37− property bool locked: shown && multiUser && !greeterContentLoader.promptless
37+ property alias promptless: greeterContentLoader.promptless
38+ property bool locked: shown && multiUser && !promptless
3839
3940 readonly property bool narrowMode: !multiUser && width <= units.gu(60)
4041 readonly property bool multiUser: LightDM.Users.count > 1
GreeterShell.qmlnew file+170
@@ -0,0 +1,170 @@
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.Application 0.1
19+import LightDM 0.1 as LightDM
20+import "Greeter"
21+import "Launcher"
22+import "Panel"
23+import "Components"
24+import "Components/Math.js" as MathLocal
25+
26+BasicShell {
27+ id: shell
28+
29+ function activateApplication(desktopFile, argument) {
30+ greeter.login()
31+ // TODO: support opening the app once inside user's session
32+ }
33+
34+ Lockscreen {
35+ id: lockscreen
36+ hides: [launcher, panel.indicators]
37+ shown: false
38+ enabled: true
39+ showAnimation: StandardAnimation { property: "opacity"; to: 1 }
40+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
41+ y: panel.panelHeight
42+ x: required ? 0 : - width
43+ width: parent.width
44+ height: parent.height - panel.panelHeight
45+ background: shell.background
46+
47+ onUnlocked: lockscreen.hide()
48+ onCancel: greeter.show()
49+
50+ Component.onCompleted: {
51+ if (LightDM.Users.count == 1) {
52+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
53+ }
54+ }
55+ }
56+
57+ Connections {
58+ target: LightDM.Greeter
59+
60+ onShowPrompt: {
61+ if (LightDM.Users.count == 1) {
62+ // TODO: There's no better way for now to determine if its a PIN or a passphrase.
63+ if (text == "PIN") {
64+ lockscreen.alphaNumeric = false
65+ } else {
66+ lockscreen.alphaNumeric = true
67+ }
68+ lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
69+ lockscreen.show();
70+ }
71+ }
72+ }
73+
74+ Greeter {
75+ id: greeter
76+
77+ available: true
78+ hides: [launcher, panel.indicators]
79+ shown: true
80+
81+ y: panel.panelHeight
82+ width: parent.width
83+ height: parent.height - panel.panelHeight
84+
85+ dragHandleWidth: shell.edgeSize
86+
87+ function login() {
88+ enabled = false;
89+ LightDM.Greeter.startSessionSync();
90+ }
91+
92+ onUnlocked: login()
93+ onShownChanged: {
94+ if (shown) {
95+ lockscreen.reset();
96+ // If there is only one user, we start authenticating with that one here.
97+ // If there are more users, the Greeter will handle that
98+ if (LightDM.Users.count == 1) {
99+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
100+ }
101+ greeter.forceActiveFocus();
102+ }
103+ else if (promptless)
104+ login();
105+ }
106+ onSelected: {
107+ var bgPath = greeter.model.data(uid, LightDM.UserRoles.BackgroundPathRole)
108+ shell.background = bgPath ? bgPath : default_background
109+ }
110+
111+ onLeftTeaserPressedChanged: {
112+ if (leftTeaserPressed) {
113+ launcher.tease();
114+ }
115+ }
116+ }
117+
118+ InputFilterArea {
119+ anchors.fill: parent
120+ blockInput: true
121+ }
122+
123+ Revealer {
124+ id: greeterRevealer
125+ objectName: "greeterRevealer"
126+
127+ property real animatedProgress: MathLocal.clamp(-dragPosition / closedValue, 0, 1)
128+ target: greeter
129+ width: greeter.width
130+ height: greeter.height
131+ handleSize: shell.edgeSize
132+ orientation: Qt.Horizontal
133+ enabled: !greeter.locked
134+ }
135+
136+ Item {
137+ id: overlay
138+
139+ anchors.fill: parent
140+
141+ Panel {
142+ id: panel
143+ anchors.fill: parent //because this draws indicator menus
144+ indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
145+ indicators {
146+ hides: [launcher]
147+ }
148+ fullscreenMode: false
149+ searchVisible: false
150+ }
151+
152+ Launcher {
153+ id: launcher
154+
155+ anchors.top: parent.top
156+ anchors.bottom: parent.bottom
157+ width: parent.width
158+ dragAreaWidth: shell.edgeSize
159+ available: !greeter.locked
160+ onLauncherApplicationSelected: {
161+ shell.activateApplication(name)
162+ }
163+ onShownChanged: {
164+ if (shown) {
165+ panel.indicators.hide()
166+ }
167+ }
168+ }
169+ }
170+}
Hud/Hud.qml+1−4
@@ -227,10 +227,7 @@ Item {
227227 width: parent.width
228228
229229 onYChanged: {
230− if (greeter.shown) {
231− showAnimation.duration = 0
232− hideAnimation.duration = 0
233− } else if (!showAnimation.running && !hideAnimation.running) {
230+ if (!showAnimation.running && !hideAnimation.running) {
234231 if (parent.height > 0) {
235232 showAnimation.duration = Math.min(showableAnimationDuration * (1 - (parent.height - y) / parent.height), showableAnimationDuration)
236233 hideAnimation.duration = showableAnimationDuration - showAnimation.duration
Shell.qml+9−152
@@ -18,9 +18,8 @@ import QtQuick 2.0
1818import Ubuntu.Application 0.1
1919import Ubuntu.Components 0.1
2020import Ubuntu.Gestures 0.1
21−import LightDM 0.1 as LightDM
21+import SessionManager 0.1
2222import "Dash"
23−import "Greeter"
2423import "Launcher"
2524import "Panel"
2625import "Hud"
@@ -31,17 +30,9 @@ import "SideStage"
3130import "Notifications"
3231import Unity.Notifications 1.0 as NotificationBackend
3332
34−FocusScope {
33+BasicShell {
3534 id: shell
3635
37− // this is only here to select the width / height of the window if not running fullscreen
38− property bool tablet: false
39− width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
40− height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
41−
42− property real edgeSize: units.gu(2)
43− property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
44− property url background: default_background
4536 readonly property real panelHeight: panel.panelHeight
4637
4738 property bool dashShown: dash.shown
@@ -72,9 +63,7 @@ FocusScope {
7263 }
7364
7465 readonly property bool fullscreenMode: {
75− if (greeter.shown || lockscreen.shown) {
76− return false;
77− } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
66+ if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
7867 return mainStage.switchingFromFullscreenToFullscreen;
7968 } else if (applicationManager.mainStageFocusedApplication) {
8069 return applicationManager.mainStageFocusedApplication.fullscreen;
@@ -87,9 +76,6 @@ FocusScope {
8776 target: applicationManager
8877 ignoreUnknownSignals: true
8978 onFocusRequested: {
90− // TODO: this should be protected to only unlock for certain applications / certain usecases
91− // potentially only in connection with a notification
92− greeter.hide();
9379 shell.activateApplication(desktopFile);
9480 }
9581 }
@@ -114,16 +100,9 @@ FocusScope {
114100 }
115101 }
116102
117− VolumeControl {
118− id: volumeControl
119− }
120−
121− Keys.onVolumeUpPressed: volumeControl.volumeUp()
122− Keys.onVolumeDownPressed: volumeControl.volumeDown()
123−
124103 Keys.onReleased: {
125104 if (event.key == Qt.Key_PowerOff) {
126− greeter.show()
105+ SessionManager.lock()
127106 }
128107 }
129108
@@ -162,7 +141,6 @@ FocusScope {
162141 id: dash
163142 objectName: "dash"
164143
165− available: !greeter.shown && !lockscreen.shown
166144 hides: [stages, launcher, panel.indicators]
167145 shown: disappearingAnimationProgress !== 1.0
168146 enabled: disappearingAnimationProgress === 0.0
@@ -180,16 +158,10 @@ FocusScope {
180158
181159 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
182160 opacity: 1.0 - disappearingAnimationProgress
183− property real disappearingAnimationProgress: {
184− if (greeter.shown) {
185− return greeter.showProgress;
186− } else {
187− return stagesOuterContainer.showProgress;
188− }
189− }
161+ property real disappearingAnimationProgress: stagesOuterContainer.showProgress
190162
191− // FIXME: only necessary because stagesOuterContainer.showProgress and
192− // greeterRevealer.animatedProgress are not animated
163+ // FIXME: only necessary because stagesOuterContainer.showProgress
164+ // is not animated
193165 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
194166 }
195167 }
@@ -214,7 +186,6 @@ FocusScope {
214186
215187 property bool fullyShown: shown && x == 0 && parent.x == 0
216188 property bool fullyHidden: !shown && x == width
217− available: !greeter.shown
218189 hides: [launcher, panel.indicators]
219190 shown: false
220191 opacity: 1.0
@@ -317,7 +288,7 @@ FocusScope {
317288 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
318289 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
319290
320− available: !greeter.shown && !lockscreen.shown && enabled
291+ available: enabled
321292 hides: [launcher, panel.indicators]
322293 shown: false
323294 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
@@ -367,106 +338,6 @@ FocusScope {
367338 }
368339 }
369340
370− Lockscreen {
371− id: lockscreen
372− hides: [launcher, panel.indicators, hud]
373− shown: false
374− enabled: true
375− showAnimation: StandardAnimation { property: "opacity"; to: 1 }
376− hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
377− y: panel.panelHeight
378− x: required ? 0 : - width
379− width: parent.width
380− height: parent.height - panel.panelHeight
381− background: shell.background
382−
383− onUnlocked: lockscreen.hide()
384− onCancel: greeter.show()
385−
386− Component.onCompleted: {
387− if (LightDM.Users.count == 1) {
388− LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
389− }
390− }
391− }
392−
393− Connections {
394− target: LightDM.Greeter
395−
396− onShowPrompt: {
397− if (LightDM.Users.count == 1) {
398− // TODO: There's no better way for now to determine if its a PIN or a passphrase.
399− if (text == "PIN") {
400− lockscreen.alphaNumeric = false
401− } else {
402− lockscreen.alphaNumeric = true
403− }
404− lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
405− lockscreen.show();
406− }
407− }
408− }
409−
410− Greeter {
411− id: greeter
412−
413− available: true
414− hides: [launcher, panel.indicators, hud]
415− shown: true
416−
417− y: panel.panelHeight
418− width: parent.width
419− height: parent.height - panel.panelHeight
420−
421− dragHandleWidth: shell.edgeSize
422−
423− property var previousMainApp: null
424− property var previousSideApp: null
425−
426− onShownChanged: {
427− if (shown) {
428− lockscreen.reset();
429− // If there is only one user, we start authenticating with that one here.
430− // If there are more users, the Greeter will handle that
431− if (LightDM.Users.count == 1) {
432− LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
433− }
434− greeter.forceActiveFocus();
435− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
436− // the stage was actually shown
437− if (mainStage.fullyShown) greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
438− if (sideStage.fullyShown) greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
439− applicationManager.unfocusCurrentApplication();
440− } else {
441− if (greeter.previousMainApp) {
442− applicationManager.focusApplication(greeter.previousMainApp);
443− greeter.previousMainApp = null;
444− }
445− if (greeter.previousSideApp) {
446− applicationManager.focusApplication(greeter.previousSideApp);
447− greeter.previousSideApp = null;
448− }
449− }
450− }
451−
452− onUnlocked: greeter.hide()
453− onSelected: {
454− var bgPath = greeter.model.data(uid, LightDM.UserRoles.BackgroundPathRole)
455− shell.background = bgPath ? bgPath : default_background
456− }
457−
458− onLeftTeaserPressedChanged: {
459− if (leftTeaserPressed) {
460− launcher.tease();
461− }
462− }
463− }
464−
465− InputFilterArea {
466− anchors.fill: parent
467− blockInput: greeter.shown || lockscreen.shown
468− }
469−
470341 Item {
471342 id: overlay
472343
@@ -480,7 +351,6 @@ FocusScope {
480351 hides: [launcher]
481352 }
482353 fullscreenMode: shell.fullscreenMode
483− searchVisible: !greeter.shown && !lockscreen.shown
484354
485355 InputFilterArea {
486356 anchors.fill: parent
@@ -494,7 +364,7 @@ FocusScope {
494364 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
495365 height: parent.height
496366
497− available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown
367+ available: !panel.indicators.shown
498368 shown: false
499369 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
500370 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
@@ -552,9 +422,7 @@ FocusScope {
552422 anchors.bottom: parent.bottom
553423 width: parent.width
554424 dragAreaWidth: shell.edgeSize
555− available: !greeter.locked
556425 onDashItemSelected: {
557− greeter.hide()
558426 // Animate if moving between application and dash
559427 if (!stages.shown) {
560428 dash.setCurrentScope("home.scope", true, false)
@@ -571,7 +439,6 @@ FocusScope {
571439 }
572440 }
573441 onLauncherApplicationSelected:{
574− greeter.hide()
575442 shell.activateApplication(desktopFile)
576443 }
577444 onShownChanged: {
@@ -622,16 +489,6 @@ FocusScope {
622489 blockInput: true
623490 }
624491
625− InputFilterArea {
626− anchors {
627− top: parent.top
628− bottom: parent.bottom
629− right: parent.right
630− }
631− width: shell.edgeSize
632− blockInput: true
633− }
634−
635492 Binding {
636493 target: i18n
637494 property: "domain"
debian/control+13
@@ -3,6 +3,7 @@ Section: x11
33Priority: optional
44Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
55Build-Depends: cmake,
6+ dbus-test-runner,
67 debhelper (>= 9),
78 libdee-qt5-dev (>= 3.0),
89 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
@@ -12,6 +13,7 @@ Build-Depends: cmake,
1213 libjson-perl,
1314 libnm-glib-dev,
1415 libnm-util-dev,
16+ liblightdm-qt5-3-dev,
1517 libpulse-dev,
1618 libqmenumodel-dev,
1719 libqt5v8-5-private-dev,
@@ -27,6 +29,7 @@ Build-Depends: cmake,
2729 python3,
2830 qt5-default,
2931 qtbase5-dev,
32+ qtbase5-dev-tools,
3033 qtbase5-private-dev,
3134 qtdeclarative5-dev,
3235 qtdeclarative5-dev-tools,
@@ -75,6 +78,15 @@ Recommends: indicator-battery,
7578Description: Unity 8 shell
7679 The Unity 8 shell is the primary user interface for Ubuntu devices.
7780
81+Package: unity8-greeter
82+Architecture: any
83+Depends: ubuntu-touch-session,
84+ unity8 (>= ${source:Version}),
85+ ${misc:Depends},
86+ ${shlibs:Depends},
87+Description: Ubuntu QML greeter
88+ The Ubuntu QML greeter is the primary greeter for Ubuntu devices.
89+
7890Package: unity8-autopilot
7991Architecture: all
8092Depends: indicators-client (>= ${source:Version}),
@@ -84,6 +96,7 @@ Depends: indicators-client (>= ${source:Version}),
8496 python-evdev,
8597 unity8 (>= ${source:Version}),
8698 unity8-fake-env (>= ${source:Version}),
99+ unity8-greeter (>= ${source:Version}),
87100 ${misc:Depends},
88101 ${python:Depends},
89102 ${shlibs:Depends},
debian/copyright+1−1
@@ -22,7 +22,7 @@ License: GPL-3
2222 On Debian systems, the full text of the GNU General Public License
2323 version 3 can be found in the file /usr/share/common-licenses/GPL-3.
2424
25−Files: tests/mocks/LightDM/UsersModel.h tests/mocks/LightDM/Greeter.h
25+Files: tests/mocks/liblightdm/UsersModel.h tests/mocks/liblightdm/Greeter.h
2626Copyright: 2013 Canonical Ltd.
2727 2010-2011 David Edmundson
2828 2010-2011 Robert Ancell
debian/rules+2−5
@@ -8,7 +8,8 @@ export NO_PNG_PKG_MANGLE=1
88
99SCOPES_RECOMMENDS := $(shell perl debian/scopes-recommends-generator /usr/share/unity/client-scopes.json)
1010
11−%:
11+.PHONY: build
12+build %:
1213 dh $@ --parallel --fail-missing --with python2
1314
1415override_dh_auto_clean:
@@ -28,9 +29,5 @@ override_dh_install:
2829override_dh_makeshlibs:
2930 dh_makeshlibs -Nunity8-private -Nunity8-fake-env
3031
31−# libMockLightDM-qml.so links against liblightdm-qt5-2.so which doesn't exist
32−override_dh_shlibdeps:
33− dh_shlibdeps -XlibMockLightDM-qml.so
34−
3532override_dh_gencontrol:
3633 dh_gencontrol -- -Vunity-default-masterscopes="$(SCOPES_RECOMMENDS)"
debian/unity8-greeter.installnew file+4
@@ -0,0 +1,4 @@
1+usr/bin/unity8-greeter
2+usr/share/xgreeters/unity8-greeter.desktop
3+usr/share/unity8/GreeterShell.qml
4+usr/share/unity8/Greeter
debian/unity8-greeter.postinstnew file+12
@@ -0,0 +1,12 @@
1+#!/bin/sh
2+set -e
3+
4+case "$1" in
5+configure|upgrade|reconfigure)
6+ if [ -x /usr/lib/lightdm/lightdm-set-defaults ] ; then
7+ /usr/lib/lightdm/lightdm-set-defaults --keep-old --greeter=unity8-greeter --session=ubuntu-touch || true
8+ fi
9+ ;;
10+esac
11+
12+#DEBHELPER#
debian/unity8-greeter.prermnew file+12
@@ -0,0 +1,12 @@
1+#!/bin/sh
2+set -e
3+
4+case "$1" in
5+remove|purge)
6+ if [ -x /usr/lib/lightdm/lightdm-set-defaults ] ; then
7+ /usr/lib/lightdm/lightdm-set-defaults --remove --greeter=unity8-greeter --session=ubuntu-touch || true
8+ fi
9+ ;;
10+esac
11+
12+#DEBHELPER#
debian/unity8-private.install+1
@@ -1,6 +1,7 @@
11usr/lib/*/unity8/qml/HudClient
22usr/lib/*/unity8/qml/LightDM
33usr/lib/*/unity8/qml/ListViewWithPageHeader
4+usr/lib/*/unity8/qml/SessionManager
45usr/lib/*/unity8/qml/Ubuntu
56usr/lib/*/unity8/qml/Unity
67usr/lib/*/unity8/qml/Utils
debian/unity8.install−1
@@ -5,7 +5,6 @@ usr/share/unity8/Applications
55usr/share/unity8/Bottombar
66usr/share/unity8/Components
77usr/share/unity8/Dash
8−usr/share/unity8/Greeter
98usr/share/unity8/Hud
109usr/share/unity8/Launcher
1110usr/share/unity8/Notifications
main.cpp+8−3
@@ -22,6 +22,7 @@
2222#include <QtQuick/QQuickView>
2323#include <QtGui/QIcon>
2424#include <QtGui/QGuiApplication>
25+#include <QtGui/QScreen>
2526#include <QtQml/QQmlEngine>
2627#include <QtQml/QQmlContext>
2728#include <qpa/qplatformnativeinterface.h>
@@ -82,7 +83,7 @@ int main(int argc, char** argv)
8283 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
8384 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
8485
85− QGuiApplication::setApplicationName("Unity 8");
86+ QGuiApplication::setApplicationName(APP_NAME);
8687 QGuiApplication application(argc, argv);
8788
8889 resolveIconTheme();
@@ -111,7 +112,7 @@ int main(int argc, char** argv)
111112
112113 QQuickView* view = new QQuickView();
113114 view->setResizeMode(QQuickView::SizeRootObjectToView);
114− view->setTitle("Qml Phone Shell");
115+ view->setTitle(APP_NAME);
115116 view->engine()->setBaseUrl(QUrl::fromLocalFile(::shellAppDirectory()));
116117 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
117118 if (args.contains(QLatin1String("-frameless"))) {
@@ -136,13 +137,17 @@ int main(int argc, char** argv)
136137 nativeInterface->setProperty("ubuntuSessionType", 1);
137138 view->setProperty("role", 2); // INDICATOR_ACTOR_ROLE
138139
139− QUrl source("Shell.qml");
140+ QUrl source(QML_FILE);
140141 prependImportPaths(view->engine(), ::overrideImportPaths());
141142 appendImportPaths(view->engine(), ::fallbackImportPaths());
142143 view->setSource(source);
143144 view->setColor("transparent");
144145
145146 if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || args.contains(QLatin1String("-fullscreen"))) {
147+ // First, size window equal to screen (fake a real WM fullscreen mode).
148+ // Then, in case we are actually running inside a windowing system,
149+ // nicely set actual WM fullscreen hint for its benefit.
150+ view->resize(view->screen()->size());
146151 view->showFullScreen();
147152 } else {
148153 view->show();
plugins/CMakeLists.txt+1
@@ -4,3 +4,4 @@ add_subdirectory(Unity)
44add_subdirectory(HudClient)
55add_subdirectory(LightDM)
66add_subdirectory(ListViewWithPageHeader)
7+add_subdirectory(SessionManager)
plugins/LightDM/CMakeLists.txt+5−9
@@ -3,20 +3,18 @@ include(Plugins)
33
44# Dependencies
55include(FindPkgConfig)
6+pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-3)
67pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
7−# TODO: Once we split out a separate greeter process, uncomment these lines
8−#pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-2)
98
109include_directories(
1110 ${CMAKE_CURRENT_SOURCE_DIR}
1211 ${CMAKE_CURRENT_BINARY_DIR}
13− ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
14− #${LIBLIGHTDM_INCLUDE_DIRS}
12+ ${LIBLIGHTDM_INCLUDE_DIRS}
1513 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
1614)
1715
1816set(QMLPLUGIN_SRC
19− ../Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
17+ ${CMAKE_SOURCE_DIR}/plugins/Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
2018 Greeter.cpp
2119 plugin.cpp
2220 UsersModel.cpp
@@ -27,13 +25,11 @@ add_library(LightDM-qml MODULE
2725 )
2826
2927target_link_libraries(LightDM-qml
30− MockLightDM-demo
31−# TODO: Once we split out a separate greeter process, uncomment these lines
32−# ${LIBLIGHTDM_LDFLAGS}
28+ ${LIBLIGHTDM_LDFLAGS}
3329 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
3430 )
3531
36−qt5_use_modules(LightDM-qml Gui Qml)
32+qt5_use_modules(LightDM-qml Qml)
3733
3834# export the qmldir qmltypes and plugin files
3935export_qmlfiles(LightDM LightDM)
plugins/SessionManager/CMakeLists.txtnew file+27
@@ -0,0 +1,27 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
4+set(QMLPLUGIN_SRC
5+ plugin.cpp
6+ SessionManager.cpp
7+ )
8+
9+include_directories(
10+ ${Qt5DBus_INCLUDE_DIRS}
11+ )
12+
13+add_definitions(-DSM_BUSNAME=systemBus)
14+
15+add_library(SessionManager-qml MODULE
16+ ${QMLPLUGIN_SRC}
17+ )
18+
19+target_link_libraries(SessionManager-qml
20+ ${Qt5DBus_LIBRARIES}
21+ )
22+
23+qt5_use_modules(SessionManager-qml Qml)
24+
25+# export the qmldir qmltypes and plugin files
26+export_qmlfiles(SessionManager SessionManager)
27+export_qmlplugin(SessionManager 0.1 SessionManager TARGETS SessionManager-qml)
plugins/SessionManager/SessionManager.cppnew file+105
@@ -0,0 +1,105 @@
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()) {
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+ ldm_session = new QDBusInterface("org.freedesktop.DisplayManager",
42+ QString(qgetenv("XDG_SESSION_PATH")),
43+ "org.freedesktop.DisplayManager.Session",
44+ QDBusConnection::SM_BUSNAME(), this);
45+}
46+
47+bool SessionManager::active() const
48+{
49+ // We cache this value for performance reasons, as QDBusInterface does not
50+ // cache for us.
51+ return is_active;
52+}
53+
54+void SessionManager::lock()
55+{
56+ // We use ldm_session to handle locking rather than l1_session, because
57+ // l1_session doesn't have permissions to lock from the user session, but
58+ // ldm_session does. This is what the rest of Ubuntu uses to lock.
59+ if (ldm_session != NULL && ldm_session->isValid())
60+ ldm_session->asyncCall("Lock");
61+}
62+
63+void SessionManager::getSessionSlot(QDBusPendingCallWatcher *watcher)
64+{
65+ QDBusPendingReply<QDBusObjectPath> reply = *watcher;
66+ if (!reply.isError()) {
67+ QDBusObjectPath path = reply.argumentAt<0>();
68+ l1_session = new QDBusInterface("org.freedesktop.login1",
69+ path.path(),
70+ "org.freedesktop.login1.Session",
71+ l1_manager->connection(), this);
72+
73+ l1_manager->connection().connect("org.freedesktop.login1",
74+ path.path(),
75+ "org.freedesktop.DBus.Properties",
76+ "PropertiesChanged",
77+ this,
78+ SLOT(propertiesChanged(QString, QVariantMap, QStringList)));
79+
80+ propertiesChanged("", QVariantMap(), QStringList() << "Active");
81+ }
82+ watcher->deleteLater();
83+}
84+
85+void SessionManager::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
86+{
87+ Q_UNUSED(interface)
88+
89+ QVariant value = changed.value("Active");
90+
91+ // If Active isn't in changed, check if we were at least notified about it
92+ // changing on the server. Also check if IdleHint was modified, because
93+ // sometimes logind does not emit a changed signal for Active becoming
94+ // false, but will emit for IdleHint when that does happen.
95+ if (!value.isValid() && (invalid.contains("Active") || invalid.contains("IdleHint") || changed.contains("IdleHint")) && l1_session->isValid()) {
96+ value = l1_session->property("Active");
97+ if (!value.isValid())
98+ value = QVariant(false);
99+ }
100+
101+ if (value.isValid() && value.toBool() != is_active) {
102+ is_active = value.toBool();
103+ Q_EMIT activeChanged();
104+ }
105+}
plugins/SessionManager/SessionManager.hnew file+58
@@ -0,0 +1,58 @@
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+
34+ Q_PROPERTY(bool active READ active NOTIFY activeChanged FINAL)
35+
36+public:
37+ explicit SessionManager(QObject *parent = 0);
38+
39+ bool active() const;
40+
41+public Q_SLOTS:
42+ void lock();
43+
44+Q_SIGNALS:
45+ void activeChanged();
46+
47+private Q_SLOTS:
48+ void getSessionSlot(QDBusPendingCallWatcher *watcher);
49+ void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
50+
51+private:
52+ QDBusInterface *l1_manager;
53+ QDBusInterface *l1_session;
54+ QDBusInterface *ldm_session;
55+ bool is_active;
56+};
57+
58+#endif
plugins/SessionManager/plugin.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "plugin.h"
21+#include "SessionManager.h"
22+#include <QtQml>
23+
24+static QObject *sessionmanager_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25+{
26+ Q_UNUSED(engine)
27+ Q_UNUSED(scriptEngine)
28+ return new SessionManager();
29+}
30+
31+void SessionManagerPlugin::registerTypes(const char *uri)
32+{
33+ Q_ASSERT(uri == QLatin1String("SessionManager"));
34+ qmlRegisterSingletonType<SessionManager>(uri, 0, 1, "SessionManager", sessionmanager_provider);
35+}
plugins/SessionManager/plugin.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef SESSIONMANAGER_PLUGIN_H
21+#define SESSIONMANAGER_PLUGIN_H
22+
23+#include <QtQml/QQmlEngine>
24+#include <QtQml/QQmlExtensionPlugin>
25+
26+class SessionManagerPlugin : public QQmlExtensionPlugin
27+{
28+ Q_OBJECT
29+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30+
31+public:
32+ void registerTypes(const char *uri);
33+};
34+
35+#endif
plugins/SessionManager/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module SessionManager
2+plugin SessionManager-qml
run+6−4
@@ -15,13 +15,14 @@ usage() {
1515 echo " -p, --pinlock Use a pin protected user." >&2
1616 echo " -k, --keylock Use a passphrase protected user." >&2
1717 echo " -g, --gdb Run through gdb." >&2
18+ echo " -G, --greeter Run the greeter instead of the shell." >&2
1819 echo " -h, --help Show this help." >&2
1920 echo " -m, --nomousetouch Run without -mousetouch argument." >&2
2021 echo >&2
2122 exit 1
2223}
2324
24−ARGS=`getopt -n$0 -u -a --longoptions="fake,pinlock,keylock,gdb,help,nomousetouch" -o "fpkghm" -- "$@"`
25+ARGS=`getopt -n$0 -u -a --longoptions="fake,pinlock,keylock,gdb,greeter,help,nomousetouch" -o "fpkgGhm" -- "$@"`
2526[ $? -ne 0 ] && usage
2627eval set -- "$ARGS"
2728
@@ -32,6 +33,7 @@ do
3233 -p|--pinlock) PINLOCK=true;;
3334 -k|--keylock) KEYLOCK=true;;
3435 -g|--gdb) GDB=true;;
36+ -G|--greeter) QML_PHONE_SHELL_PATH=./builddir/unity8-greeter;;
3537 -h|--help) usage;;
3638 -m|--nomousetouch) MOUSE_TOUCH=false;;
3739 --) shift;break;;
@@ -41,17 +43,17 @@ done
4143
4244if $FAKE; then
4345 export QML2_IMPORT_PATH=$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
44− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single
46+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single
4547fi
4648
4749if $PINLOCK; then
4850 export 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/LightDM/single-pin
51+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single-pin
5052fi
5153
5254if $KEYLOCK; then
5355 export 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/LightDM/single-passphrase
56+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/liblightdm/single-passphrase
5557fi
5658
5759# Force icon theme if running on the desktop, otherwise gnome theme (if running
tests/autopilot/unity8/shell/tests/__init__.py+22−5
@@ -41,6 +41,7 @@ from unity8 import (
4141)
4242from unity8.shell.emulators import UnityEmulatorBase
4343from unity8.shell.emulators.dash import Dash
44+from unity8.shell.emulators.greeter import Greeter
4445from unity8.shell.emulators.main_window import MainWindow
4546
4647
@@ -148,9 +149,8 @@ class UnityTestCase(AutopilotTestCase):
148149 divisor = divisor * 2
149150 return divisor
150151
151− def launch_unity(self):
152− """Launch the unity shell, return a proxy object for it."""
153− binary_path = get_binary_path()
152+ def _launch(self, executable, ready_func):
153+ binary_path = get_binary_path(executable)
154154 lib_path = get_lib_path()
155155
156156 logger.info(
@@ -173,11 +173,19 @@ class UnityTestCase(AutopilotTestCase):
173173
174174 # Ensure that the dash is visible before we return:
175175 logger.debug("Unity started, waiting for it to be ready.")
176− self.assertUnityReady()
176+ ready_func()
177177 logger.debug("Unity loaded and ready.")
178178
179179 return app_proxy
180180
181+ def launch_unity(self):
182+ """Launch the unity shell, return a proxy object for it."""
183+ return self._launch("unity8", self.assertUnityReady)
184+
185+ def launch_greeter(self):
186+ """Launch the unity shell, return a proxy object for it."""
187+ return self._launch("unity8-greeter", self.assertGreeterReady)
188+
181189 def patch_lightdm_mock(self, mock_type='single'):
182190 self._lightdm_mock_type = mock_type
183191 logger.info("Setting up LightDM mock type '%s'", mock_type)
@@ -192,7 +200,7 @@ class UnityTestCase(AutopilotTestCase):
192200 def _get_lightdm_mock_path(self, mock_type):
193201 lib_path = get_mocks_library_path()
194202 lightdm_mock_path = os.path.abspath(
195− os.path.join(lib_path, "LightDM", mock_type)
203+ os.path.join(lib_path, "liblightdm", mock_type)
196204 )
197205
198206 if not os.path.exists(lightdm_mock_path):
@@ -229,11 +237,20 @@ class UnityTestCase(AutopilotTestCase):
229237 )
230238 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
231239
240+ def assertGreeterReady(self):
241+ greeter = self.get_greeter()
242+ self.assertThat(greeter.created, Eventually(Equals(True)))
243+
232244 def get_dash(self):
233245 dash = self._proxy.select_single(Dash)
234246 self.assertThat(dash, NotEquals(None))
235247 return dash
236248
249+ def get_greeter(self):
250+ greeter = self._proxy.select_single(Greeter)
251+ self.assertThat(greeter, NotEquals(None))
252+ return greeter
253+
237254 @property
238255 def main_window(self):
239256 return MainWindow(self._proxy)
tests/autopilot/unity8/shell/tests/test_hud.py−6
@@ -19,7 +19,6 @@
1919
2020from __future__ import absolute_import
2121
22−from unity8.shell import with_lightdm_mock
2322from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
2423
2524from testtools.matchers import Equals
@@ -37,7 +36,6 @@ class TestHud(UnityTestCase):
3736
3837 """
3938 self.launch_unity()
40− self.main_window.get_greeter().unlock()
4139 window = self.main_window.get_qml_view()
4240 hud_show_button = self.main_window.get_hud_show_button()
4341 hud = self.main_window.get_hud()
@@ -58,7 +56,6 @@ class TestHud(UnityTestCase):
5856
5957 """
6058 self.launch_unity()
61− self.main_window.get_greeter().unlock()
6259 window = self.main_window.get_qml_view()
6360 hud_show_button = self.main_window.get_hud_show_button()
6461 hud = self.main_window.get_hud()
@@ -81,7 +78,6 @@ class TestHud(UnityTestCase):
8178 def test_hide_hud_click(self):
8279 """Tapping the close button of the Hud must dismiss it."""
8380 self.launch_unity()
84− self.main_window.get_greeter().unlock()
8581 hud = self.main_window.get_hud()
8682
8783 self._launch_test_app_from_app_screen()
@@ -97,7 +93,6 @@ class TestHud(UnityTestCase):
9793
9894 """
9995 self.launch_unity()
100− self.main_window.get_greeter().unlock()
10196 hud = self.main_window.get_hud()
10297 window = self.main_window.get_qml_view()
10398
@@ -114,7 +109,6 @@ class TestHud(UnityTestCase):
114109 def test_launcher_hides_hud(self):
115110 """Opening the Launcher while the Hud is active must close the Hud."""
116111 self.launch_unity()
117− self.main_window.get_greeter().unlock()
118112 hud = self.main_window.get_hud()
119113 launcher = self.main_window.get_launcher()
120114
tests/autopilot/unity8/shell/tests/test_lock_screen.py+4−4
@@ -38,7 +38,7 @@ class TestLockscreen(UnityTestCase):
3838 @with_lightdm_mock("single-pin")
3939 def test_can_unlock_pin_screen(self):
4040 """Must be able to unlock the PIN entry lock screen."""
41− self.launch_unity()
41+ self.launch_greeter()
4242 greeter = self.main_window.get_greeter()
4343 greeter.unlock()
4444
@@ -50,7 +50,7 @@ class TestLockscreen(UnityTestCase):
5050 @with_lightdm_mock("single-passphrase")
5151 def test_can_unlock_passphrase_screen(self):
5252 """Must be able to unlock the passphrase entry screen."""
53− self.launch_unity()
53+ self.launch_greeter()
5454 greeter = self.main_window.get_greeter()
5555 greeter.unlock()
5656
@@ -62,7 +62,7 @@ class TestLockscreen(UnityTestCase):
6262 @with_lightdm_mock("single-pin")
6363 def test_pin_screen_wrong_code(self):
6464 """Entering the wrong pin code must not dismiss the lock screen."""
65− self.launch_unity()
65+ self.launch_greeter()
6666 greeter = self.main_window.get_greeter()
6767 greeter.unlock()
6868
@@ -76,7 +76,7 @@ class TestLockscreen(UnityTestCase):
7676 @with_lightdm_mock("single-passphrase")
7777 def test_passphrase_screen_wrong_password(self):
7878 """Entering the wrong password must not dismiss the lock screen."""
79− self.launch_unity()
79+ self.launch_greeter()
8080 greeter = self.main_window.get_greeter()
8181 greeter.unlock()
8282
tests/mocks/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
1+add_subdirectory(liblightdm)
12add_subdirectory(libusermetrics)
2−add_subdirectory(LightDM)
33add_subdirectory(QMenuModel)
44add_subdirectory(Ubuntu)
55add_subdirectory(Unity)
tests/mocks/LightDM/CMakeLists.txtdeleted−55
@@ -1,55 +0,0 @@
1−# This is a copy of the normal LightDM plugin, but instead of statically
2−# linking in the lightdm bits, this one uses shared libraries so we can swap
3−# out different sets of users for different tests. When we finally switch to
4−# actually using the system liblightdm in the normal plugin, this version can
5−# be deleted.
6−
7−add_subdirectory(demo)
8−add_subdirectory(full)
9−add_subdirectory(single)
10−add_subdirectory(single-pin)
11−add_subdirectory(single-passphrase)
12−
13−include_directories(
14− ${CMAKE_CURRENT_SOURCE_DIR}
15− ${CMAKE_CURRENT_BINARY_DIR}
16− ${CMAKE_SOURCE_DIR}/tests/mocks/libusermetrics
17−)
18−
19−set(QMLPLUGIN_SRC
20− ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
21− ${CMAKE_SOURCE_DIR}/plugins/LightDM/plugin.cpp
22− ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp
23− ${CMAKE_SOURCE_DIR}/plugins/Utils/qsortfilterproxymodelqml.cpp
24− )
25−
26−add_library(MockLightDM-qml MODULE
27− ${QMLPLUGIN_SRC}
28− )
29−
30−# We want to link to liblightdm-qt5-2, but we don't want to depend on it being
31−# installed on the system. So we make sure we link to our full fake version
32−# At run time, we can point to whichever version we happen to be using via
33−# LD_LIBRARY_PATH.
34−add_dependencies(MockLightDM-qml MockLightDM-full)
35−target_link_libraries(MockLightDM-qml
36− -L${CMAKE_CURRENT_BINARY_DIR}/full
37− -llightdm-qt5-2
38− -L${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics
39− -lusermetricsoutput
40− )
41−
42−qt5_use_modules(MockLightDM-qml Gui Qml)
43−
44−# copy qmldir file into build directory for shadow builds
45−file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
46− DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
47− )
48−
49−install(TARGETS MockLightDM-qml
50− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM
51− )
52−
53−install(FILES qmldir
54− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM
55− )
tests/mocks/liblightdm/CMakeLists.txtnew file+4
@@ -0,0 +1,4 @@
1+add_subdirectory(full)
2+add_subdirectory(single)
3+add_subdirectory(single-pin)
4+add_subdirectory(single-passphrase)
tests/mocks/LightDM/Greeter.cpp → tests/mocks/liblightdm/Greeter.cpprenamed

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

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

The content is the same.

tests/plugins/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1+add_subdirectory(SessionManager)
12add_subdirectory(Utils)
23add_subdirectory(Ubuntu)
34add_subdirectory(Unity)
tests/plugins/SessionManager/CMakeLists.txtnew file+48
@@ -0,0 +1,48 @@
1+macro(make_dbus_class PREFIX SERVICE INTERFACE)
2+ if (${CMAKE_CURRENT_SOURCE_DIR}/interfaces.xml IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}${INTERFACE}Adaptor.h)
3+ execute_process(COMMAND qdbusxml2cpp -c ${PREFIX}${INTERFACE}Adaptor -a ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}${INTERFACE}Adaptor ${CMAKE_CURRENT_SOURCE_DIR}/interfaces.xml ${SERVICE}.${INTERFACE})
4+ endif ()
5+endmacro(make_dbus_class)
6+
7+make_dbus_class(LightDM org.freedesktop.DisplayManager Session)
8+make_dbus_class(Login org.freedesktop.login1 Manager)
9+make_dbus_class(Login org.freedesktop.login1 Session)
10+make_dbus_class(Login org.freedesktop.DBus Properties)
11+
12+include_directories(
13+ ${CMAKE_CURRENT_BINARY_DIR}
14+ ${CMAKE_SOURCE_DIR}/plugins/SessionManager
15+ )
16+
17+add_definitions(-DSM_BUSNAME=sessionBus)
18+
19+add_executable(mock-server
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(mock-server Core DBus)
30+
31+add_executable(test-sessionmanager
32+ ${CMAKE_SOURCE_DIR}/plugins/SessionManager/SessionManager.cpp
33+ client.cpp
34+ )
35+qt5_use_modules(test-sessionmanager Core DBus Test)
36+
37+add_test(NAME test-sessionmanager
38+ COMMAND env
39+ XDG_SESSION_ID=sessionid
40+ XDG_SESSION_PATH=/mocksession/lightdm
41+ dbus-test-runner
42+ --task ${CMAKE_CURRENT_BINARY_DIR}/mock-server
43+ --task-name server
44+ --ignore-return
45+ --task ${CMAKE_CURRENT_BINARY_DIR}/test-sessionmanager
46+ --task-name client
47+ --wait-for org.freedesktop.login1
48+ )
tests/plugins/SessionManager/LightDMSessionServer.cppnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LightDMSessionServer.h"
21+
22+LightDMSessionServer::LightDMSessionServer(LoginSessionServer *logind, QObject *parent)
23+ : QObject(parent),
24+ logind(logind)
25+{
26+}
27+
28+void LightDMSessionServer::Lock()
29+{
30+ // As a side effect of locking, change Active state of logind.
31+ // Note that this will say Active is true while the Active property will be
32+ // false. This is intentional, as we don't want to keep any state in the
33+ // mocks. Having this signal side effect lets us test that lock() was
34+ // actually called by the plugin as well as test the changed signal itself.
35+ QVariantMap changes;
36+ changes.insert("Active", QVariant(true));
37+ Q_EMIT logind->PropertiesChanged("org.freedesktop.login1.Session", changes, QStringList());
38+}
tests/plugins/SessionManager/LightDMSessionServer.hnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_LIGHTDMSESSIONSERVER_H
21+#define UNITY_LIGHTDMSESSIONSERVER_H
22+
23+#include "LoginSessionServer.h"
24+#include <QtCore/QObject>
25+
26+class LightDMSessionServer: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit LightDMSessionServer(LoginSessionServer *logind, QObject *parent = 0);
32+
33+public Q_SLOTS:
34+ void Lock();
35+
36+private:
37+ LoginSessionServer *logind;
38+};
39+
40+#endif
tests/plugins/SessionManager/LoginManagerServer.cppnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LoginManagerServer.h"
21+
22+LoginManagerServer::LoginManagerServer(QObject *parent)
23+ : QObject(parent)
24+{
25+}
26+
27+QDBusObjectPath LoginManagerServer::GetSession(const QString &id)
28+{
29+ if (id == "sessionid") {
30+ return QDBusObjectPath("/mocksession/login1");
31+ } else {
32+ return QDBusObjectPath();
33+ }
34+}
tests/plugins/SessionManager/LoginManagerServer.hnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_LOGINMANAGERSERVER_H
21+#define UNITY_LOGINMANAGERSERVER_H
22+
23+#include <QtCore/QObject>
24+#include <QtDBus/QDBusObjectPath>
25+
26+class LoginManagerServer: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit LoginManagerServer(QObject *parent = 0);
32+
33+public Q_SLOTS:
34+ QDBusObjectPath GetSession(const QString &id);
35+};
36+
37+#endif
tests/plugins/SessionManager/LoginSessionServer.cppnew file+25
@@ -0,0 +1,25 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LoginSessionServer.h"
21+
22+LoginSessionServer::LoginSessionServer(QObject *parent)
23+ : QObject(parent)
24+{
25+}
tests/plugins/SessionManager/LoginSessionServer.hnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_LOGINSESSIONSERVER_H
21+#define UNITY_LOGINSESSIONSERVER_H
22+
23+#include <QtCore/QObject>
24+#include <QtCore/QStringList>
25+#include <QtCore/QVariant>
26+#include <QtCore/QVariantMap>
27+
28+class LoginSessionServer: public QObject
29+{
30+ Q_OBJECT
31+
32+public:
33+ explicit LoginSessionServer(QObject *parent = 0);
34+
35+Q_SIGNALS:
36+ void PropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
37+};
38+
39+#endif
tests/plugins/SessionManager/client.cppnew file+88
@@ -0,0 +1,88 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "SessionManager.h"
21+#include <QtTest/QSignalSpy>
22+#include <QtTest/QTest>
23+
24+
25+// These tests assume the following behavior from our mock logind server:
26+// * IsActive will return false
27+// * Lock() will emit an ActiveChanged(true) signal
28+//
29+// This should lead to the following behavior from our SessionManager plugin:
30+// * Starts active
31+// * Becomes inactive once it connects to logind and sees IsActive result
32+// * Becomes active once Lock() is called (which isn't really sensible, but
33+// it's just a mock)
34+
35+class SessionManagerTest : public QObject
36+{
37+ Q_OBJECT
38+
39+private Q_SLOTS:
40+
41+ void waitForChange(SessionManager *session)
42+ {
43+ // Wait 5 seconds for initial activeChanged signal
44+ QSignalSpy spy(session, SIGNAL(activeChanged()));
45+ int i = 0;
46+ while (spy.count() == 0 && i++ < 50)
47+ QTest::qWait(100);
48+ QCOMPARE(spy.count(), 1);
49+ }
50+
51+ void testAssumeActive()
52+ {
53+ // Test that active() starts as true before we connect to service
54+ SessionManager session;
55+ QCOMPARE(session.active(), true);
56+ }
57+
58+ void testSafeLock()
59+ {
60+ // Test that lock() doesn't crash if used before we connect to service
61+ // (i.e. just test that we're not being stupid about pointers)
62+ SessionManager session;
63+ session.lock();
64+ }
65+
66+ void testInitialSignal()
67+ {
68+ // Test that we get notified of change once we connect to service
69+ SessionManager session;
70+ waitForChange(&session);
71+ QCOMPARE(session.active(), false);
72+ }
73+
74+ void testLock()
75+ {
76+ // Test that lock() gets called correctly and that we listen for
77+ // the activeChanged signal too.
78+ SessionManager session;
79+ waitForChange(&session);
80+ session.lock();
81+ waitForChange(&session);
82+ QCOMPARE(session.active(), true);
83+ }
84+};
85+
86+QTEST_MAIN(SessionManagerTest)
87+
88+#include "client.moc"
tests/plugins/SessionManager/interfaces.xmlnew file+22
@@ -0,0 +1,22 @@
1+<node>
2+ <interface name="org.freedesktop.login1.Manager">
3+ <method name="GetSession">
4+ <arg name="id" type="s" direction="in" />
5+ <arg name="path" type="o" direction="out" />
6+ </method>
7+ </interface>
8+ <interface name="org.freedesktop.login1.Session">
9+ <property name="Active" type="b" access="read"/>
10+ </interface>
11+ <interface name="org.freedesktop.DBus.Properties">
12+ <signal name="PropertiesChanged">
13+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
14+ <arg name="interface" type="s" direction="out"/>
15+ <arg name="changed" type="a{sv}" direction="out"/>
16+ <arg name="invalid" type="as" direction="out"/>
17+ </signal>
18+ </interface>
19+ <interface name="org.freedesktop.DisplayManager.Session">
20+ <method name="Lock"/>
21+ </interface>
22+</node>
tests/plugins/SessionManager/server.cppnew file+57
@@ -0,0 +1,57 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * version 3 along with this program. If not, see
15+ * <http://www.gnu.org/licenses/>
16+ *
17+ * Authored by: Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "LightDMSessionAdaptor.h"
21+#include "LightDMSessionServer.h"
22+#include "LoginManagerAdaptor.h"
23+#include "LoginManagerServer.h"
24+#include "LoginPropertiesAdaptor.h"
25+#include "LoginSessionAdaptor.h"
26+#include "LoginSessionServer.h"
27+#include <QtCore/QCoreApplication>
28+
29+int main(int argc, char *argv[])
30+{
31+ QCoreApplication a(argc, argv);
32+
33+ LoginManagerServer *manager = new LoginManagerServer();
34+ new LoginManagerAdaptor(manager);
35+
36+ LoginSessionServer *l1_session = new LoginSessionServer();
37+ new LoginSessionAdaptor(l1_session);
38+ new LoginPropertiesAdaptor(l1_session);
39+
40+ LightDMSessionServer *ldm_session = new LightDMSessionServer(l1_session);
41+ new LightDMSessionAdaptor(ldm_session);
42+
43+ // We use the session bus for testing. The real plugin uses the system bus
44+ QDBusConnection connection = QDBusConnection::sessionBus();
45+ if (!connection.registerObject("/org/freedesktop/login1", manager))
46+ return 1;
47+ if (!connection.registerObject("/mocksession/login1", l1_session))
48+ return 1;
49+ if (!connection.registerObject("/mocksession/lightdm", ldm_session))
50+ return 1;
51+ if (!connection.registerService("org.freedesktop.DisplayManager"))
52+ return 1;
53+ if (!connection.registerService("org.freedesktop.login1"))
54+ return 1;
55+
56+ return a.exec();
57+}
tests/qmltests/CMakeLists.txt+20−28
@@ -4,6 +4,7 @@ include(QmlTest)
44add_subdirectory(Components)
55
66set(qmltest_DEFAULT_IMPORT_PATHS
7+ ${CMAKE_BINARY_DIR}/plugins
78 ${CMAKE_BINARY_DIR}/tests/utils/modules
89 ${CMAKE_BINARY_DIR}/tests/mocks
910)
@@ -27,45 +28,36 @@ set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
2728set(qmltest_DEFAULT_PROPERTIES "")
2829
2930add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
30− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
31+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/single")
3132add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
3233add_qml_test(Components DraggingArea)
33−add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
34+add_qml_test(Components FilterGrid)
3435add_qml_test(Components ResponsiveFlowView)
3536add_qml_test(Components ResponsiveGridView)
3637add_qml_test(Components Revealer)
3738add_qml_test(Components Showable)
38−add_qml_test(Components Stage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
39− ${CMAKE_BINARY_DIR}/tests/mocks
40− ${CMAKE_BINARY_DIR}/plugins)
39+add_qml_test(Components Stage)
4140add_qml_test(Components Tile)
4241add_qml_test(Components PageHeader)
43−add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
44−add_qml_test(Dash DashBar IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
45−add_qml_test(Dash DashContent IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS})
42+add_qml_test(Dash Dash)
43+add_qml_test(Dash DashBar)
44+add_qml_test(Dash DashContent)
4645add_qml_test(Dash DashPreview)
47−add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
48−add_qml_test(Dash ScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
49−add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins
50− ${CMAKE_BINARY_DIR}/tests/mocks)
51−add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
52−add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
53− PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
54−add_qml_test(Greeter Tablet IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
55− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
56−add_qml_test(Greeter Phone IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
57− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
58−add_qml_test(Greeter Infographics IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
59− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
46+add_qml_test(Dash GenericScopeView)
47+add_qml_test(Dash ScopeView)
48+add_qml_test(Dash FilterGrids)
49+add_qml_test(Dash/Apps RunningApplicationsGrid)
50+add_qml_test(Greeter Lockscreen ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
51+add_qml_test(Greeter Tablet ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
52+add_qml_test(Greeter Phone ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/single")
53+add_qml_test(Greeter Infographics ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/liblightdm/full")
6054add_qml_test(Hud Hud)
6155add_qml_test(Hud Result)
62−add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
63−add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
56+add_qml_test(Launcher Launcher)
57+add_qml_test(Notifications Notifications)
6458add_qml_test(Panel IndicatorRow)
65−add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
59+add_qml_test(Panel Indicators)
6660add_qml_test(Panel MenuContent)
67−add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
61+add_qml_test(Panel Panel)
6862add_qml_test(Panel SearchIndicator)
69−add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
70− ${CMAKE_BINARY_DIR}/tests/mocks
71− ${CMAKE_BINARY_DIR}/plugins)
63+add_qml_test(SideStage SideStage)
unity8-greeter.desktop.innew file+10
@@ -0,0 +1,10 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Unity 8 Greeter
4+GenericName=unity8-greeter
5+Comment=The converged Unity greeter
6+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/ubuntu-touch-session @CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity8-greeter -fullscreen
7+Terminal=false
8+Icon=unity8
9+NoDisplay=true
10+X-Ubuntu-Touch=true