on xenial help sign in
Merge greeter-manual-login
commit9a8a24ce11400f9594d9bf8bdbc4053e75b9ff12 authorMichael Terry <mike@mterry.name> dateThu 19 Jan 2017, 10:37 (10 years ago) parent65bfae327fa2c9
11 files changed+155−51
plugins/LightDM/Greeter.cpp+5 plugins/LightDM/IntegratedLightDM/liblightdm/Greeter.cpp+7−4 plugins/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.cpp+27−22 plugins/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.h+1 qml/Greeter/LoginList.qml−2 qml/Greeter/WideView.qml+1−4 tests/mocks/liblightdm/MockController.cpp+24 tests/mocks/liblightdm/MockController.h+15 tests/mocks/liblightdm/MockUsersModel.cpp+42−19 tests/mocks/liblightdm/MockUsersModel.h+2 tests/qmltests/Greeter/tst_WideView.qml+31
plugins/LightDM/Greeter.cpp+5
@@ -17,6 +17,7 @@
1717
1818#include "Greeter.h"
1919#include "GreeterPrivate.h"
20+#include <QCoreApplication>
2021#include <libintl.h>
2122
2223static Greeter *singleton = nullptr;
@@ -43,6 +44,10 @@ Greeter::Greeter(QObject* parent)
4344 connect(d->m_greeter, &QLightDM::Greeter::authenticationComplete,
4445 this, &Greeter::authenticationCompleteFilter);
4546
47+ // Don't get stuck waiting for PAM as we shut down.
48+ connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
49+ d->m_greeter, &QLightDM::Greeter::cancelAuthentication);
50+
4651 d->m_greeter->connectSync();
4752}
4853
plugins/LightDM/IntegratedLightDM/liblightdm/Greeter.cpp+7−4
@@ -49,7 +49,7 @@ QString Greeter::authenticationUser() const
4949
5050bool Greeter::hasGuestAccountHint() const
5151{
52− return true;
52+ return false;
5353}
5454
5555QString Greeter::getHint(const QString &name) const
@@ -70,12 +70,12 @@ bool Greeter::hideUsersHint() const
7070
7171bool Greeter::showManualLoginHint() const
7272{
73− return true;
73+ return false;
7474}
7575
7676bool Greeter::showRemoteLoginHint() const
7777{
78− return true;
78+ return false;
7979}
8080
8181QString Greeter::selectUserHint() const
@@ -146,7 +146,10 @@ void Greeter::authenticateRemote(const QString &session, const QString &username
146146}
147147
148148void Greeter::cancelAuthentication()
149−{}
149+{
150+ Q_D(Greeter);
151+ d->cancelAuthentication();
152+}
150153
151154void Greeter::setLanguage (const QString &language)
152155{
plugins/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.cpp+27−22
@@ -206,6 +206,28 @@ public Q_SLOTS:
206206 }
207207 }
208208
209+ void cancelPam()
210+ {
211+ if (pamHandle != nullptr) {
212+ QFuture<int> pamFuture = futureWatcher.future();
213+ pam_handle *handle = pamHandle;
214+ pamHandle = nullptr; // to disable normal finishPam() handling
215+ pamFuture.cancel();
216+
217+ // Note the empty loop, we just want to clear the futures queue.
218+ // Any further prompts from the pam thread will be immediately
219+ // responded to/dismissed in handlePrompt().
220+ while (respond(QString()));
221+
222+ // Now let signal/slot handling happen so the thread can finish
223+ while (!pamFuture.isFinished()) {
224+ QCoreApplication::processEvents();
225+ }
226+
227+ pam_end(handle, PAM_CONV_ERR);
228+ }
229+ }
230+
209231Q_SIGNALS:
210232 void showMessage(pam_handle *handle, QString text, QLightDM::Greeter::MessageType type);
211233 void showPrompt(pam_handle *handle, QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture response);
@@ -247,28 +269,6 @@ private Q_SLOTS:
247269 }
248270
249271private:
250− void cancelPam()
251− {
252− if (pamHandle != nullptr) {
253− QFuture<int> pamFuture = futureWatcher.future();
254− pam_handle *handle = pamHandle;
255− pamHandle = nullptr; // to disable normal finishPam() handling
256− pamFuture.cancel();
257−
258− // Note the empty loop, we just want to clear the futures queue.
259− // Any further prompts from the pam thread will be immediately
260− // responded to/dismissed in handlePrompt().
261− while (respond(QString()));
262−
263− // Now let signal/slot handling happen so the thread can finish
264− while (!pamFuture.isFinished()) {
265− QCoreApplication::processEvents();
266− }
267−
268− pam_end(handle, PAM_CONV_ERR);
269− }
270− }
271−
272272 Greeter *greeter;
273273 GreeterPrivate *greeterPrivate;
274274 pam_handle* pamHandle;
@@ -299,6 +299,11 @@ void GreeterPrivate::handleRespond(const QString &response)
299299 m_impl->respond(response);
300300}
301301
302+void GreeterPrivate::cancelAuthentication()
303+{
304+ m_impl->cancelPam();
305+}
306+
302307}
303308
304309#include "GreeterPrivate.moc"
plugins/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.h+1
@@ -38,6 +38,7 @@ public:
3838
3939 void handleAuthenticate();
4040 void handleRespond(const QString &response);
41+ void cancelAuthentication();
4142
4243protected:
4344 GreeterImpl *m_impl; // if the backend needs more private data
qml/Greeter/LoginList.qml−2
@@ -35,11 +35,9 @@ StyledItem {
3535 readonly property int cellHeight: units.gu(5)
3636 readonly property int highlightedHeight: highlightItem.height
3737 readonly property int moveDuration: UbuntuAnimation.FastDuration
38− property string selectedSession
3938 property string currentSession
4039 readonly property string currentUser: userList.currentItem.username
4140
42− signal loginListSessionChanged(string session)
4341 signal responded(string response)
4442 signal selected(int index)
4543 signal sessionChooserButtonClicked()
qml/Greeter/WideView.qml+1−4
@@ -115,8 +115,6 @@ FocusScope {
115115 id: loginList
116116 objectName: "loginList"
117117
118− property int selectedUserIndex: 0
119−
120118 width: units.gu(40)
121119 anchors {
122120 left: parent.left
@@ -131,11 +129,10 @@ FocusScope {
131129 Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
132130
133131 model: root.userModel
134− currentSession: LightDMService.users.data(selectedUserIndex, LightDMService.userRoles.SessionRole);
135132 onResponded: root.responded(response)
136133 onSelected: {
137134 root.selected(index)
138− loginList.selectedUserIndex = index;
135+ currentSession = LightDMService.users.data(index, LightDMService.userRoles.SessionRole);
139136 }
140137 onSessionChooserButtonClicked: parent.state = "SessionsList"
141138
tests/mocks/liblightdm/MockController.cpp+24
@@ -152,6 +152,30 @@ void MockController::setUserMode(const QString &userMode)
152152 }
153153}
154154
155+QString MockController::sessionName() const
156+{
157+ return QString("INVALID - Please read directly from the UserModel");
158+}
159+
160+void MockController::setSessionName(const QString &sessionName)
161+{
162+ // Let the user model deal with this
163+ Q_EMIT sessionNameChanged(sessionName, m_currentUsername);
164+}
165+
166+QString MockController::currentUsername() const
167+{
168+ return m_currentUsername;
169+}
170+
171+void MockController::setCurrentUsername(const QString &username)
172+{
173+ if (m_currentUsername != username) {
174+ m_currentUsername = username;
175+ Q_EMIT currentUsernameChanged();
176+ }
177+}
178+
155179QString MockController::sessionMode() const
156180{
157181 return m_sessionMode;
tests/mocks/liblightdm/MockController.h+15
@@ -38,6 +38,11 @@ class Q_DECL_EXPORT MockController : public QObject
3838 // single, none, full
3939 Q_PROPERTY(QString sessionMode READ sessionMode WRITE setSessionMode NOTIFY sessionModeChanged)
4040
41+ // This would be best as a Q_INVOKABLE, but using a property allows for
42+ // keeping the mock cleaner
43+ Q_PROPERTY(QString sessionName READ sessionName WRITE setSessionName NOTIFY sessionNameChanged)
44+ Q_PROPERTY(QString currentUsername READ currentUsername WRITE setCurrentUsername NOTIFY currentUsernameChanged)
45+
4146 Q_PROPERTY(int numAvailableSessions READ numFullSessions CONSTANT)
4247 Q_PROPERTY(int numSessions READ numSessions WRITE setNumSessions NOTIFY numSessionsChanged)
4348
@@ -68,6 +73,12 @@ public:
6873 QString sessionMode() const;
6974 void setSessionMode(const QString &sessionMode);
7075
76+ QString sessionName() const;
77+ void setSessionName(const QString &userIndex);
78+
79+ QString currentUsername() const;
80+ void setCurrentUsername(const QString &username);
81+
7182 class SessionItem
7283 {
7384 public:
@@ -81,6 +92,7 @@ public:
8192 void setNumSessions(int numSessions);
8293
8394Q_SIGNALS:
95+ void currentUsernameChanged();
8496 void selectUserHintChanged();
8597 void selectGuestHintChanged();
8698 void hasGuestAccountHintChanged();
@@ -89,10 +101,13 @@ Q_SIGNALS:
89101 void userModeChanged();
90102 void sessionModeChanged();
91103 void numSessionsChanged();
104+ void sessionNameChanged(const QString &sessionName, const QString &username);
92105
93106private:
94107 explicit MockController(QObject* parent=0);
95108
109+ QString m_currentUsername;
110+ QString m_sessionName;
96111 QString m_selectUserHint;
97112 bool m_selectGuestHint;
98113 bool m_hasGuestAccountHint;
tests/mocks/liblightdm/MockUsersModel.cpp+42−19
@@ -73,6 +73,8 @@ UsersModel::UsersModel(QObject *parent)
7373 this, &UsersModel::resetEntries);
7474 connect(MockController::instance(), &MockController::userModeChanged,
7575 this, &UsersModel::resetEntries);
76+ connect(MockController::instance(), &MockController::sessionNameChanged,
77+ this, &UsersModel::setCurrentSessionName);
7678 resetEntries();
7779}
7880
@@ -81,6 +83,22 @@ UsersModel::~UsersModel()
8183 delete d_ptr;
8284}
8385
86+void UsersModel::setCurrentSessionName(const QString &sessionName, const QString &username)
87+{
88+ Q_D(UsersModel);
89+
90+ int usersIndex = 0;
91+ for (auto &entry : d->entries) {
92+ if (username == entry.username) {
93+ entry.session = sessionName;
94+ break;
95+ }
96+ usersIndex++;
97+ }
98+
99+ dataChanged(index(usersIndex, 0), index(usersIndex, 0), QVector<int>(SessionRole));
100+}
101+
84102int UsersModel::rowCount(const QModelIndex &parent) const
85103{
86104 Q_D(const UsersModel);
@@ -144,33 +162,38 @@ void UsersModel::resetEntries()
144162 } else if (userMode == "single-pin") {
145163 d->entries = {{"has-pin", "Has PIN", "", 0, false, false, "ubuntu", 0}};
146164 } else if (userMode == "full") {
165+ /*
166+ * Since the real model sorts these entries alphabetically, the model indices
167+ * don't line up correctly. The easiest way to fix this is to ensure that this
168+ * list of entries REMAINS IN ALPHABETICAL ORDER at all times.
169+ */
147170 d->entries = {
171+ { "active", "Active Account", 0, 0, true, false, "ubuntu", 0 },
172+ { "auth-error", "Auth Error", 0, 0, false, false, "ubuntu", 0 },
173+ { "black-background", "Black Background", "#000000", 0, false, false, "ubuntu", 0 },
174+ { "color-background", "Color Background", "#E95420", 0, false, false, "ubuntu", 0 },
175+ { "different-prompt", "Different Prompt", 0, 0, false, false, "ubuntu", 0 },
176+ { "empty-name", "", 0, 0, false, false, "ubuntu", 0 },
148177 { "has-password", "Has Password", 0, 0, false, false, "ubuntu", 0 },
149178 { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0 },
150− { "different-prompt", "Different Prompt", 0, 0, false, false, "ubuntu", 0 },
151− { "question-prompt", "Question Prompt", 0, 0, false, false, "ubuntu", 0 },
152− { "no-password", "No Password", 0, 0, false, false, "ubuntu", 0 },
153− { "auth-error", "Auth Error", 0, 0, false, false, "ubuntu", 0 },
154− { "two-factor", "Two Factor", 0, 0, false, false, "ubuntu", 0 },
155− { "two-prompts", "Two Prompts", 0, 0, false, false, "ubuntu", 0 },
156− { "wacky-prompts", "Interspersed Prompts", 0, 0, false, false, "ubuntu", 0 },
157− { "info-prompt", "Info Prompt", 0, 0, false, false, "ubuntu", 0 },
158179 { "html-info-prompt", "HTML Info Prompt", 0, 0, false, false, "ubuntu", 0 },
159− { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, "ubuntu", 0 },
160− { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, "ubuntu", 0 },
161− { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, "ubuntu", 0 },
162180 { "info-after-login", "Info After Login", 0, 0, false, false, "ubuntu", 0 },
181+ { "info-prompt", "Info Prompt", 0, 0, false, false, "ubuntu", 0 },
182+ { "wacky-prompts", "Interspersed Prompts", 0, 0, false, false, "ubuntu", 0 },
183+ { "locked", "Locked", 0, 0, false, false, "ubuntu", 0 },
184+ { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, "ubuntu", 0 },
163185 { "long-name", "Long name (far far too long to fit, seriously this would never fit on the screen, you will never see this part of the name)", 0, 0, false, false, "ubuntu", 0 },
164− { "color-background", "Color Background", "#E95420", 0, false, false, "ubuntu", 0 },
165− // white and black are a bit redundant, but useful for manually testing if UI is still readable
166− { "white-background", "White Background", "#ffffff", 0, false, false, "ubuntu", 0 },
167− { "black-background", "Black Background", "#000000", 0, false, false, "ubuntu", 0 },
186+ { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, "ubuntu", 0 },
168187 { "no-background", "No Background", "", 0, false, false, "ubuntu", 0 },
169− { "unicode", "가나다라마", 0, 0, false, false, "ubuntu", 0 },
188+ { "no-password", "No Password", 0, 0, false, false, "ubuntu", 0 },
170189 { "no-response", "No Response", 0, 0, false, false, "ubuntu", 0 },
171− { "empty-name", "", 0, 0, false, false, "ubuntu", 0 },
172− { "active", "Active Account", 0, 0, true, false, "ubuntu", 0 },
173− { "locked", "Locked", 0, 0, false, false, "ubuntu", 0 },
190+ { "question-prompt", "Question Prompt", 0, 0, false, false, "ubuntu", 0 },
191+ { "two-factor", "Two Factor", 0, 0, false, false, "ubuntu", 0 },
192+ { "two-prompts", "Two Prompts", 0, 0, false, false, "ubuntu", 0 },
193+ // white and black are a bit redundant, but useful for manually testing if UI is still readable
194+ { "white-background", "White Background", "#ffffff", 0, false, false, "ubuntu", 0 },
195+ { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, "ubuntu", 0 },
196+ { "unicode", "가나다라마", 0, 0, false, false, "ubuntu", 0 }
174197 };
175198 }
176199
tests/mocks/liblightdm/MockUsersModel.h+2
@@ -48,6 +48,8 @@ public:
4848 int rowCount(const QModelIndex &parent) const override;
4949 QVariant data(const QModelIndex &index, int role) const override;
5050
51+ void setCurrentSessionName(const QString &sessionName, const QString &username);
52+
5153private Q_SLOTS:
5254 void resetEntries();
5355
tests/qmltests/Greeter/tst_WideView.qml+31
@@ -393,6 +393,37 @@ StyledItem {
393393 waitForRendering(view);
394394 }
395395
396+ function test_changingSessionSticksToUser() {
397+ LightDMController.sessionMode = "full";
398+
399+ var loginList = findChild(view, "loginList");
400+ var fakeSession1 = "ASessionWillNeverBeCalledThis";
401+ var fakeSession2 = "ASessionWillAlsoNeverBeCalledThis";
402+
403+ // For this test to work, a user has to be selected and the
404+ // mock must be made aware of that user
405+ selectUser("has-password")
406+ LightDMController.currentUsername = "has-password"
407+ compare(LightDM.Sessions.count > 1, true);
408+ compare(loginList.currentSession != fakeSession1, true);
409+ LightDMController.sessionName = fakeSession1;
410+
411+ selectUser("has-pin")
412+ LightDMController.currentUsername = "has-pin"
413+ compare(loginList.currentSession != fakeSession2, true);
414+ LightDMController.sessionName = fakeSession2;
415+
416+ selectUser("has-password")
417+ tryCompare(loginList, "currentSession", fakeSession1);
418+
419+ selectUser("has-pin")
420+ tryCompare(loginList, "currentSession", fakeSession2);
421+
422+ // Force a model reset
423+ LightDMController.userMode = "single";
424+ LightDMController.userMode = "full";
425+ }
426+
396427 function test_tease_data() {
397428 return [
398429 {tag: "locked", x: 0, offset: 0, count: 0, locked: true},