2 * Copyright (C) 2013,2014,2015 Canonical, Ltd.
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.
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.
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/>.
18 import AccountsService 0.1
19 import LightDM 0.1 as LightDM
20 import Ubuntu.Components 1.1
21 import Ubuntu.SystemImage 0.1
22 import Unity.Launcher 0.1
23 import "../Components"
27 created: loader.status == Loader.Ready
29 property real dragHandleLeftMargin: 0
31 property url background
33 // How far to offset the top greeter layer during a launcher left-drag
34 property real launcherOffset
36 readonly property bool active: shown || hasLockedApp
37 readonly property bool fullyShown: loader.item ? loader.item.fullyShown : false
39 // True when the greeter is waiting for PAM or other setup process
40 readonly property alias waiting: d.waiting
42 property string lockedApp: ""
43 readonly property bool hasLockedApp: lockedApp !== ""
45 property bool forcedUnlock
46 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock
48 property bool tabletMode
49 property url viewSource // only used for testing
51 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
52 property int failedLoginsDelayAttempts: 7 // number of failed logins
53 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
55 readonly property bool animating: loader.item ? loader.item.animating : false
58 signal sessionStarted()
59 signal emergencyCall()
61 function forceShow() {
66 function notifyAppFocused(appId) {
72 if (appId === lockedApp) {
73 hide(); // show locked app
76 d.startUnlock(false /* toTheRight */);
78 } else if (appId !== "unity8-dash") { // dash isn't started by user
79 d.startUnlock(false /* toTheRight */);
83 function notifyAboutToFocusApp(appId) {
88 // A hint that we're about to focus an app. This way we can look
89 // a little more responsive, rather than waiting for the above
90 // notifyAppFocused call. We also need this in case we have a locked
91 // app, in order to show lockscreen instead of new app.
92 d.startUnlock(false /* toTheRight */);
95 // This is a just a glorified notifyAboutToFocusApp(), but it does one
96 // other thing: it hides any cover pages to the RIGHT, because the user
97 // just came from a launcher drag starting on the left.
98 // It also returns a boolean value, indicating whether there was a visual
99 // change or not (the shell only wants to hide the launcher if there was
101 function notifyShowingDashFromDrag() {
106 return d.startUnlock(true /* toTheRight */);
112 readonly property bool multiUser: LightDM.Users.count > 1
113 property int currentIndex
114 property bool waiting
116 // We want 'launcherOffset' to animate down to zero. But not to animate
117 // while being dragged. So ideally we change this only when the user
118 // lets go and launcherOffset drops to zero. But we need to wait for
119 // the behavior to be enabled first. So we cache the last known good
120 // launcherOffset value to cover us during that brief gap between
121 // release and the behavior turning on.
122 property real lastKnownPositiveOffset // set in a launcherOffsetChanged below
123 property real launcherOffsetProxy: (shown && !launcherOffsetProxyBehavior.enabled) ? lastKnownPositiveOffset : 0
124 Behavior on launcherOffsetProxy {
125 id: launcherOffsetProxyBehavior
126 enabled: launcherOffset === 0
127 UbuntuNumberAnimation {}
130 function selectUser(uid, reset) {
136 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
137 AccountsService.user = user;
138 LauncherModel.setUser(user);
139 LightDM.Greeter.authenticate(user); // always resets auth state
144 if (LightDM.Greeter.startSessionSync()) {
147 loader.item.notifyAuthenticationSucceeded();
149 } else if (loader.item) {
150 loader.item.notifyAuthenticationFailed();
155 function startUnlock(toTheRight) {
157 return loader.item.tryToUnlock(toTheRight);
164 onLauncherOffsetChanged: {
165 if (launcherOffset > 0) {
166 d.lastKnownPositiveOffset = launcherOffset;
170 onForcedUnlockChanged: {
171 if (forcedUnlock && shown) {
172 // pretend we were just authenticated
173 loader.item.notifyAuthenticationSucceeded();
187 // We use a short interval and check against the system wall clock
188 // because we have to consider the case that the system is suspended
189 // for a few minutes. When we wake up, we want to quickly be correct.
192 property var delayTarget;
193 property int delayMinutes;
195 function forceDelay(delay /* in minutes */) {
196 delayTarget = new Date();
197 delayTarget.setTime(delayTarget.getTime() + delay * 60000);
198 delayMinutes = Math.ceil(delay);
203 var diff = delayTarget - new Date();
205 delayMinutes = Math.ceil(diff / 60000);
214 // Nothing should leak to items behind the greeter
215 MouseArea { anchors.fill: parent }
223 active: root.required
224 source: root.viewSource.toString() ? root.viewSource :
225 (d.multiUser || root.tabletMode) ? "WideView.qml" : "NarrowView.qml"
229 root.forceActiveFocus();
230 d.selectUser(d.currentIndex, true);
231 LightDM.Infographic.readyForDataChange();
237 d.selectUser(index, true);
241 LightDM.Greeter.respond(response);
243 if (LightDM.Greeter.active && !LightDM.Greeter.authenticated) { // could happen if forcedUnlock
249 onTease: root.tease()
250 onEmergencyCall: root.emergencyCall()
252 if (!loader.item.required) {
260 property: "backgroundTopMargin"
266 property: "launcherOffset"
267 value: d.launcherOffsetProxy
272 property: "dragHandleLeftMargin"
273 value: root.dragHandleLeftMargin
278 property: "delayMinutes"
279 value: forcedDelayTimer.delayMinutes
284 property: "background"
285 value: root.background
296 property: "alphanumeric"
297 value: AccountsService.passwordDisplayHint === AccountsService.Keyboard
302 property: "currentIndex"
303 value: d.currentIndex
308 property: "userModel"
314 property: "infographicModel"
315 value: LightDM.Infographic
320 target: LightDM.Greeter
322 onShowGreeter: root.forceShow()
330 if (!LightDM.Greeter.active) {
331 return; // could happen if hideGreeter() comes in before we prompt
334 // inefficient, but we only rarely deal with messages
335 var html = text.replace(/&/g, "&")
336 .replace(/</g, "<")
337 .replace(/>/g, ">")
338 .replace(/\n/g, "<br>");
340 html = "<font color=\"#df382c\">" + html + "</font>";
343 loader.item.showMessage(html);
349 if (!LightDM.Greeter.active) {
350 return; // could happen if hideGreeter() comes in before we prompt
353 loader.item.showPrompt(text, isSecret, isDefaultPrompt);
356 onAuthenticationComplete: {
359 if (LightDM.Greeter.authenticated) {
360 AccountsService.failedLogins = 0;
362 if (!LightDM.Greeter.promptless) {
366 if (!LightDM.Greeter.promptless) {
367 AccountsService.failedLogins++;
370 // Check if we should initiate a factory reset
371 if (maxFailedLogins >= 2) { // require at least a warning
372 if (AccountsService.failedLogins === maxFailedLogins - 1) {
373 loader.item.showLastChance();
374 } else if (AccountsService.failedLogins >= maxFailedLogins) {
375 SystemImage.factoryReset(); // Ouch!
379 // Check if we should initiate a forced login delay
380 if (failedLoginsDelayAttempts > 0
381 && AccountsService.failedLogins > 0
382 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
383 forcedDelayTimer.forceDelay(failedLoginsDelayMinutes);
386 loader.item.notifyAuthenticationFailed();
387 if (!LightDM.Greeter.promptless) {
388 d.selectUser(d.currentIndex, false);
393 onRequestAuthenticationUser: {
394 // Find index for requested user, if it exists
395 for (var i = 0; i < LightDM.Users.count; i++) {
396 if (user === LightDM.Users.data(i, LightDM.UserRoles.NameRole)) {
397 d.selectUser(i, true);
405 target: LightDM.Greeter
411 target: LightDM.Infographic
413 value: AccountsService.statsWelcomeScreen ? LightDM.Users.data(d.currentIndex, LightDM.UserRoles.NameRole) : ""
418 onLanguageChanged: LightDM.Infographic.readyForDataChange()