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
56 signal sessionStarted()
57 signal emergencyCall()
59 function forceShow() {
64 function notifyAppFocused(appId) {
70 if (appId === lockedApp) {
71 hide(); // show locked app
74 d.startUnlock(false /* toTheRight */);
76 } else if (appId !== "unity8-dash") { // dash isn't started by user
77 d.startUnlock(false /* toTheRight */);
81 function notifyAboutToFocusApp(appId) {
86 // A hint that we're about to focus an app. This way we can look
87 // a little more responsive, rather than waiting for the above
88 // notifyAppFocused call. We also need this in case we have a locked
89 // app, in order to show lockscreen instead of new app.
90 d.startUnlock(false /* toTheRight */);
93 // This is a just a glorified notifyAboutToFocusApp(), but it does one
94 // other thing: it hides any cover pages to the RIGHT, because the user
95 // just came from a launcher drag starting on the left.
96 // It also returns a boolean value, indicating whether there was a visual
97 // change or not (the shell only wants to hide the launcher if there was
99 function notifyShowingDashFromDrag() {
104 return d.startUnlock(true /* toTheRight */);
110 readonly property bool multiUser: LightDM.Users.count > 1
111 property int currentIndex
112 property bool waiting
114 // We want 'launcherOffset' to animate down to zero. But not to animate
115 // while being dragged. So ideally we change this only when the user
116 // lets go and launcherOffset drops to zero. But we need to wait for
117 // the behavior to be enabled first. So we cache the last known good
118 // launcherOffset value to cover us during that brief gap between
119 // release and the behavior turning on.
120 property real lastKnownPositiveOffset // set in a launcherOffsetChanged below
121 property real launcherOffsetProxy: (shown && !launcherOffsetProxyBehavior.enabled) ? lastKnownPositiveOffset : 0
122 Behavior on launcherOffsetProxy {
123 id: launcherOffsetProxyBehavior
124 enabled: launcherOffset === 0
125 UbuntuNumberAnimation {}
128 function selectUser(uid, reset) {
134 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
135 AccountsService.user = user;
136 LauncherModel.setUser(user);
137 LightDM.Greeter.authenticate(user); // always resets auth state
142 if (LightDM.Greeter.startSessionSync()) {
144 loader.item.notifyAuthenticationSucceeded();
146 loader.item.notifyAuthenticationFailed();
151 function startUnlock(toTheRight) {
153 return loader.item.tryToUnlock(toTheRight);
160 onLauncherOffsetChanged: {
161 if (launcherOffset > 0) {
162 d.lastKnownPositiveOffset = launcherOffset;
166 onForcedUnlockChanged: {
167 if (forcedUnlock && shown) {
168 // pretend we were just authenticated
169 loader.item.notifyAuthenticationSucceeded();
183 // We use a short interval and check against the system wall clock
184 // because we have to consider the case that the system is suspended
185 // for a few minutes. When we wake up, we want to quickly be correct.
188 property var delayTarget;
189 property int delayMinutes;
191 function forceDelay(delay /* in minutes */) {
192 delayTarget = new Date();
193 delayTarget.setTime(delayTarget.getTime() + delay * 60000);
194 delayMinutes = Math.ceil(delay);
199 var diff = delayTarget - new Date();
201 delayMinutes = Math.ceil(diff / 60000);
210 // Nothing should leak to items behind the greeter
211 MouseArea { anchors.fill: parent }
219 active: root.required
220 source: root.viewSource.toString() ? root.viewSource :
221 (d.multiUser || root.tabletMode) ? "WideView.qml" : "NarrowView.qml"
225 root.forceActiveFocus();
226 d.selectUser(d.currentIndex, true);
227 LightDM.Infographic.readyForDataChange();
233 d.selectUser(index, true);
237 LightDM.Greeter.respond(response);
239 if (LightDM.Greeter.active && !LightDM.Greeter.authenticated) { // could happen if forcedUnlock
245 onTease: root.tease()
246 onEmergencyCall: root.emergencyCall()
248 if (!loader.item.required) {
256 property: "backgroundTopMargin"
262 property: "launcherOffset"
263 value: d.launcherOffsetProxy
268 property: "dragHandleLeftMargin"
269 value: root.dragHandleLeftMargin
274 property: "delayMinutes"
275 value: forcedDelayTimer.delayMinutes
280 property: "background"
281 value: root.background
292 property: "alphanumeric"
293 value: AccountsService.passwordDisplayHint === AccountsService.Keyboard
298 property: "currentIndex"
299 value: d.currentIndex
304 property: "userModel"
310 property: "infographicModel"
311 value: LightDM.Infographic
316 target: LightDM.Greeter
318 onShowGreeter: root.forceShow()
326 if (!LightDM.Greeter.active) {
327 return; // could happen if hideGreeter() comes in before we prompt
330 // inefficient, but we only rarely deal with messages
331 var html = text.replace(/&/g, "&")
332 .replace(/</g, "<")
333 .replace(/>/g, ">")
334 .replace(/\n/g, "<br>");
336 html = "<font color=\"#df382c\">" + html + "</font>";
339 loader.item.showMessage(html);
345 if (!LightDM.Greeter.active) {
346 return; // could happen if hideGreeter() comes in before we prompt
349 loader.item.showPrompt(text, isSecret, isDefaultPrompt);
352 onAuthenticationComplete: {
355 if (LightDM.Greeter.authenticated) {
356 AccountsService.failedLogins = 0;
358 if (!LightDM.Greeter.promptless) {
362 if (!LightDM.Greeter.promptless) {
363 AccountsService.failedLogins++;
366 // Check if we should initiate a factory reset
367 if (maxFailedLogins >= 2) { // require at least a warning
368 if (AccountsService.failedLogins === maxFailedLogins - 1) {
369 loader.item.showLastChance();
370 } else if (AccountsService.failedLogins >= maxFailedLogins) {
371 SystemImage.factoryReset(); // Ouch!
375 // Check if we should initiate a forced login delay
376 if (failedLoginsDelayAttempts > 0
377 && AccountsService.failedLogins > 0
378 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
379 forcedDelayTimer.forceDelay(failedLoginsDelayMinutes);
382 loader.item.notifyAuthenticationFailed();
383 if (!LightDM.Greeter.promptless) {
384 d.selectUser(d.currentIndex, false);
389 onRequestAuthenticationUser: {
390 // Find index for requested user, if it exists
391 for (var i = 0; i < LightDM.Users.count; i++) {
392 if (user === LightDM.Users.data(i, LightDM.UserRoles.NameRole)) {
393 d.selectUser(i, true);
401 target: LightDM.Greeter
407 target: LightDM.Infographic
409 value: AccountsService.statsWelcomeScreen ? LightDM.Users.data(d.currentIndex, LightDM.UserRoles.NameRole) : ""
414 onLanguageChanged: LightDM.Infographic.readyForDataChange()