2 * Copyright (C) 2013 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/>.
18import AccountsService 0.1
20import Unity.Application 0.1
21import Ubuntu.Components 0.1
22import Ubuntu.Components.Popups 1.0
23import Ubuntu.Gestures 0.1
24import Ubuntu.SystemImage 0.1
25import Ubuntu.Telephony 0.1 as Telephony
26import Unity.Connectivity 0.1
27import Unity.Launcher 0.1
29import LightDM 0.1 as LightDM
31import SessionBroadcast 0.1
38import Unity.Notifications 1.0 as NotificationBackend
39import Unity.Session 0.1
40import Unity.DashCommunicator 0.1
45 // this is only here to select the width / height of the window if not running fullscreen
46 property bool tablet: false
47 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
48 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
50 property real edgeSize: units.gu(2)
51 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
52 property url background
53 readonly property real panelHeight: panel.panelHeight
55 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated
57 property bool sideStageEnabled: shell.width >= units.gu(100)
58 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
60 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
61 property int failedLoginsDelayAttempts: 7 // number of failed logins
62 property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting
64 function activateApplication(appId) {
65 if (ApplicationManager.findApplication(appId)) {
66 ApplicationManager.requestFocusApplication(appId);
68 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
69 ApplicationManager.startApplication(appId, execFlags);
73 function setLockedApp(app) {
75 greeter.lockedApp = app
82 property: "applicationManager"
83 value: ApplicationManager
86 Component.onCompleted: {
87 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
91 id: backgroundSettings
92 schema.id: "org.gnome.desktop.background"
94 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
95 onGSettingsPictureChanged: {
96 shell.background = gSettingsPicture
105 objectName: "dashCommunicator"
109 // Handle but do not filter out volume keys
110 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
111 Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
114 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
115 dialogs.onPowerKeyPressed();
116 event.accepted = true;
118 event.accepted = false;
123 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
124 dialogs.onPowerKeyReleased();
125 event.accepted = true;
127 event.accepted = false;
136 height: parent.height
137 visible: !ApplicationManager.empty
140 target: ApplicationManager
142 if (appId === "dialer-app") {
143 // Always let the dialer-app through. Either user asked
144 // for an emergency call or accepted an incoming call.
146 } else if (greeter.hasLockedApp && greeter.lockedApp !== appId) {
153 onFocusedApplicationIdChanged: {
154 if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
157 panel.indicators.hide();
160 onApplicationAdded: {
161 if (greeter.shown && appId != "unity8-dash") {
164 if (appId === "dialer-app") {
165 // Always let the dialer-app through. Either user asked
166 // for an emergency call or accepted an incoming call.
174 id: applicationsDisplayLoader
177 // When we have a locked app, we only want to show that one app
178 source: (shell.sideStageEnabled && !greeter.hasLockedApp) ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
181 target: applicationsDisplayLoader.item
182 property: "objectName"
186 target: applicationsDisplayLoader.item
187 property: "dragAreaWidth"
188 value: shell.edgeSize
191 target: applicationsDisplayLoader.item
192 property: "maximizedAppTopMargin"
193 // Not just using panel.panelHeight as that changes depending on the focused app.
194 value: panel.indicators.panelHeight
197 target: applicationsDisplayLoader.item
198 property: "interactive"
199 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
202 target: applicationsDisplayLoader.item
203 property: "spreadEnabled"
204 value: edgeDemo.stagesEnabled && !greeter.hasLockedApp // to support emergency dialer hack
207 target: applicationsDisplayLoader.item
208 property: "inverseProgress"
209 value: launcher.progress
216 objectName: "inputMethod"
217 anchors { fill: parent; topMargin: panel.panelHeight }
218 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
222 target: SurfaceManager
224 if (surface.type == MirSurfaceItem.InputMethod) {
225 inputMethod.surface = surface;
229 onSurfaceDestroyed: {
230 if (inputMethod.surface == surface) {
231 inputMethod.surface = null;
232 surface.parent = null;
234 if (!surface.parent) {
235 // there's no one displaying it. delete it right away
241 target: SessionManager
243 if (!session.parentSession && !session.application) {
244 // nothing is using it. delete it right away
252 objectName: "lockscreen"
254 readonly property int backgroundTopMargin: -panel.panelHeight
256 hides: [launcher, panel.indicators]
259 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
260 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
264 height: parent.height - panel.panelHeight
265 background: shell.background
266 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
270 onEntered: LightDM.Greeter.respond(passphrase);
271 onCancel: greeter.show()
272 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter locked-app mode
274 onShownChanged: if (shown) greeter.lockedApp = ""
276 Component.onCompleted: {
277 if (greeter.narrowMode) {
278 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
284 target: LightDM.Greeter
286 onShowGreeter: greeter.show()
287 onHideGreeter: greeter.login()
290 if (greeter.narrowMode) {
291 if (isDefaultPrompt) {
292 if (lockscreen.alphaNumeric) {
293 lockscreen.infoText = i18n.tr("Enter your passphrase")
294 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
296 lockscreen.infoText = i18n.tr("Enter your passcode")
297 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
300 lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
301 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
308 onPromptlessChanged: {
309 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
317 onAuthenticationComplete: {
318 if (LightDM.Greeter.authenticated) {
319 AccountsService.failedLogins = 0
321 // Else only penalize user for a failed login if they actually were
322 // prompted for a password. We do this below after the promptless
325 if (LightDM.Greeter.promptless) {
329 if (LightDM.Greeter.authenticated) {
332 AccountsService.failedLogins++
333 if (maxFailedLogins >= 2) { // require at least a warning
334 if (AccountsService.failedLogins === maxFailedLogins - 1) {
335 var title = lockscreen.alphaNumeric ?
336 i18n.tr("Sorry, incorrect passphrase.") :
337 i18n.tr("Sorry, incorrect passcode.")
338 var text = i18n.tr("This will be your last attempt.") + " " +
339 (lockscreen.alphaNumeric ?
340 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
341 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
342 lockscreen.showInfoPopup(title, text)
343 } else if (AccountsService.failedLogins >= maxFailedLogins) {
344 SystemImage.factoryReset() // Ouch!
347 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
348 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
351 lockscreen.clear(true);
352 if (greeter.narrowMode) {
353 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
360 target: LightDM.Greeter
362 value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
368 opacity: greeterWrapper.showProgress * 0.8
372 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
377 height: parent.height - panel.panelHeight
380 enabled: !launcher.dashSwipe
384 property bool fullyShown: showProgress === 1.0
385 onFullyShownChanged: {
386 // Wait until the greeter is completely covering lockscreen before resetting it.
387 if (fullyShown && !LightDM.Greeter.authenticated) {
393 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
394 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
398 objectName: "greeter"
400 signal sessionStarted() // helpful for tests
402 property string lockedApp: ""
403 property bool hasLockedApp: lockedApp !== ""
406 hides: [launcher, panel.indicators]
408 loadContent: required || lockscreen.required // keeps content in memory for quick show()
410 defaultBackground: shell.background
413 height: parent.height
415 dragHandleWidth: shell.edgeSize
419 if (LightDM.Greeter.startSessionSync()) {
430 if (greeter.narrowMode) {
431 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
433 greeter.lockedApp = "";
434 greeter.forceActiveFocus();
438 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
439 Component.onCompleted: {
440 Connectivity.unlockAllModems()
443 onUnlocked: greeter.hide()
445 // Update launcher items for new user
446 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
447 AccountsService.user = user;
448 LauncherModel.setUser(user);
451 onTease: launcher.tease()
454 target: ApplicationManager
455 property: "suspended"
456 value: greeter.shown && greeterWrapper.showProgress == 1
466 if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
472 function showHome() {
473 if (edgeDemo.running) {
477 if (LightDM.Greeter.active) {
478 if (!LightDM.Greeter.authenticated) {
484 var animate = !LightDM.Greeter.active && !stages.shown
485 dash.setCurrentScope("clickscope", animate, false)
486 ApplicationManager.requestFocusApplication("unity8-dash")
489 function showDash() {
498 ApplicationManager.requestFocusApplication("unity8-dash")
511 anchors.fill: parent //because this draws indicator menus
514 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
515 contentEnabled: edgeDemo.panelContentEnabled
516 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
517 panelHeight: units.gu(3)
520 property bool topmostApplicationIsFullscreen:
521 ApplicationManager.focusedApplicationId &&
522 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
524 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
525 || greeter.hasLockedApp
530 objectName: "launcher"
532 readonly property bool dashSwipe: progress > 0
534 anchors.top: parent.top
535 anchors.bottom: parent.bottom
537 dragAreaWidth: shell.edgeSize
538 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
540 onShowDashHome: showHome()
542 onDashSwipeChanged: {
544 dash.setCurrentScope("clickscope", false, true)
547 onLauncherApplicationSelected: {
548 if (greeter.hasLockedApp) {
551 if (!edgeDemo.running)
552 shell.activateApplication(appId)
556 panel.indicators.hide()
562 id: modalNotificationBackground
564 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
577 model: NotificationBackend.Model
582 height: parent.height - panel.panelHeight
587 when: overlay.width <= units.gu(60)
588 AnchorChanges { target: notifications; anchors.left: parent.left }
592 when: overlay.width > units.gu(60)
593 AnchorChanges { target: notifications; anchors.left: undefined }
594 PropertyChanges { target: notifications; width: units.gu(38) }
605 shutdownFadeOutRectangle.enabled = true;
606 shutdownFadeOutRectangle.visible = true;
607 shutdownFadeOut.start();
612 id: alphaDisclaimerLabel
613 anchors.centerIn: parent
614 visible: ApplicationManager.fake ? ApplicationManager.fake : false
616 text: "EARLY ALPHA\nNOT READY FOR USE"
619 font.weight: Font.Black
620 horizontalAlignment: Text.AlignHCenter
621 verticalAlignment: Text.AlignVCenter
622 fontSizeMode: Text.Fit
624 scale: Math.min(parent.width, parent.height) / width
629 z: alphaDisclaimerLabel.z + 10
630 paused: Powerd.status === Powerd.Off // Saves power
633 indicators: panel.indicators
638 target: SessionBroadcast
639 onShowHome: showHome()
643 id: shutdownFadeOutRectangle
650 NumberAnimation on opacity {
655 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
656 DBusUnitySessionService.Shutdown();
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list