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 QtQuick.Window 2.0
19import AccountsService 0.1
21import Unity.Application 0.1
22import Ubuntu.Components 0.1
23import Ubuntu.Components.Popups 1.0
24import Ubuntu.Gestures 0.1
25import Ubuntu.SystemImage 0.1
26import Ubuntu.Telephony 0.1 as Telephony
27import Unity.Connectivity 0.1
28import Unity.Launcher 0.1
30import LightDM 0.1 as LightDM
32import SessionBroadcast 0.1
39import Unity.Notifications 1.0 as NotificationBackend
40import Unity.Session 0.1
41import Unity.DashCommunicator 0.1
46 // this is only here to select the width / height of the window if not running fullscreen
47 property bool tablet: false
48 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
49 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
51 property real edgeSize: units.gu(2)
52 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
53 property url background
54 readonly property real panelHeight: panel.panelHeight
56 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated
58 property bool sideStageEnabled: shell.width >= units.gu(100)
59 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
61 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
62 property int failedLoginsDelayAttempts: 7 // number of failed logins
63 property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
65 property int orientation
66 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
67 onDeviceOrientationAngleChanged: {
68 if (!OrientationLock.enabled) {
69 orientation = Screen.orientation;
72 readonly property bool orientationLockEnabled: OrientationLock.enabled
73 onOrientationLockEnabledChanged: {
74 if (orientationLockEnabled) {
75 OrientationLock.savedOrientation = Screen.orientation;
77 orientation = Screen.orientation;
81 function activateApplication(appId) {
82 if (ApplicationManager.findApplication(appId)) {
83 ApplicationManager.requestFocusApplication(appId);
85 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
86 ApplicationManager.startApplication(appId, execFlags);
90 function setLockedApp(app) {
92 greeter.lockedApp = app
99 property: "applicationManager"
100 value: ApplicationManager
103 Component.onCompleted: {
104 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
105 if (ApplicationManager.count > 0) {
106 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
108 if (orientationLockEnabled) {
109 orientation = OrientationLock.savedOrientation;
114 id: backgroundSettings
115 schema.id: "org.gnome.desktop.background"
117 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
118 onGSettingsPictureChanged: {
119 shell.background = gSettingsPicture
128 objectName: "dashCommunicator"
132 target: ApplicationManager
133 property: "forceDashActive"
134 value: launcher.shown || launcher.dashSwipe
139 // Handle but do not filter out volume keys
140 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
141 Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
144 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
145 dialogs.onPowerKeyPressed();
146 event.accepted = true;
148 event.accepted = false;
153 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
154 dialogs.onPowerKeyReleased();
155 event.accepted = true;
157 event.accepted = false;
166 height: parent.height
167 visible: !ApplicationManager.empty
170 target: ApplicationManager
172 if (greeter.narrowMode) {
173 if (appId === "dialer-app") {
174 // Always let the dialer-app through. Either user asked
175 // for an emergency call or accepted an incoming call.
177 } else if (greeter.hasLockedApp && greeter.lockedApp !== appId) {
178 greeter.startUnlock()
182 if (LightDM.Greeter.active) {
183 greeter.startUnlock()
188 onFocusedApplicationIdChanged: {
189 if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
190 greeter.startUnlock()
192 panel.indicators.hide();
195 onApplicationAdded: {
196 if (greeter.shown && appId != "unity8-dash") {
197 greeter.startUnlock()
199 if (greeter.narrowMode && appId === "dialer-app") {
200 // Always let the dialer-app through. Either user asked
201 // for an emergency call or accepted an incoming call.
209 id: applicationsDisplayLoader
210 objectName: "applicationsDisplayLoader"
213 // When we have a locked app, we only want to show that one app.
214 // FIXME: do this in a less traumatic way. We currently only allow
215 // locked apps in phone mode (see FIXME in Lockscreen component in
216 // this same file). When that changes, we need to do something
217 // nicer here. But this code is currently just to prevent a
218 // theoretical attack where user enters lockedApp mode, then makes
219 // the screen larger (maybe connects to monitor) and tries to enter
221 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
222 source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
225 target: applicationsDisplayLoader.item
226 property: "objectName"
230 target: applicationsDisplayLoader.item
231 property: "dragAreaWidth"
232 value: shell.edgeSize
235 target: applicationsDisplayLoader.item
236 property: "maximizedAppTopMargin"
237 // Not just using panel.panelHeight as that changes depending on the focused app.
238 value: panel.indicators.panelHeight
241 target: applicationsDisplayLoader.item
242 property: "interactive"
243 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
246 target: applicationsDisplayLoader.item
247 property: "spreadEnabled"
248 value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
251 target: applicationsDisplayLoader.item
252 property: "inverseProgress"
253 value: launcher.progress
256 target: applicationsDisplayLoader.item
257 property: "orientation"
258 value: shell.orientation
265 objectName: "inputMethod"
266 anchors { fill: parent; topMargin: panel.panelHeight }
267 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
271 target: SurfaceManager
273 if (surface.type == MirSurfaceItem.InputMethod) {
274 inputMethod.surface = surface;
278 onSurfaceDestroyed: {
279 if (inputMethod.surface == surface) {
280 inputMethod.surface = null;
281 surface.parent = null;
283 if (!surface.parent) {
284 // there's no one displaying it. delete it right away
290 target: SessionManager
292 if (!session.parentSession && !session.application) {
293 // nothing is using it. delete it right away
301 objectName: "lockscreen"
303 hides: [launcher, panel.indicators]
306 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
307 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
311 height: parent.height - panel.panelHeight
312 background: shell.background
313 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
317 // FIXME: We *should* show emergency dialer if there is a SIM present,
318 // regardless of whether the side stage is enabled. But right now,
319 // the assumption is that narrow screens are phones which have SIMs
320 // and wider screens are tablets which don't. When we do allow this
321 // on devices with a side stage and a SIM, work should be done to
322 // ensure that the main stage is disabled while the dialer is present
323 // in the side stage. See the FIXME in the stage loader in this file.
324 showEmergencyCallButton: !shell.sideStageEnabled
326 onEntered: LightDM.Greeter.respond(passphrase);
327 onCancel: greeter.show()
328 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter locked-app mode
330 onShownChanged: if (shown) greeter.lockedApp = ""
336 if (lockscreen.delayMinutes > 0) {
337 lockscreen.delayMinutes -= 1
338 if (lockscreen.delayMinutes > 0) {
345 Component.onCompleted: {
346 if (greeter.narrowMode) {
347 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
353 target: LightDM.Greeter
355 onShowGreeter: greeter.show()
356 onHideGreeter: greeter.login()
359 if (greeter.narrowMode) {
360 if (isDefaultPrompt) {
361 if (lockscreen.alphaNumeric) {
362 lockscreen.infoText = i18n.tr("Enter passphrase")
363 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase") + "\n" +
364 i18n.tr("Please re-enter")
366 lockscreen.infoText = i18n.tr("Enter passcode")
367 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
370 lockscreen.infoText = i18n.tr("Enter %1").arg(text.toLowerCase())
371 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
378 onPromptlessChanged: {
379 if (greeter.narrowMode) {
380 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
389 onAuthenticationComplete: {
390 if (LightDM.Greeter.authenticated) {
391 AccountsService.failedLogins = 0
393 // Else only penalize user for a failed login if they actually were
394 // prompted for a password. We do this below after the promptless
397 if (LightDM.Greeter.promptless) {
401 if (LightDM.Greeter.authenticated) {
404 AccountsService.failedLogins++
405 if (maxFailedLogins >= 2) { // require at least a warning
406 if (AccountsService.failedLogins === maxFailedLogins - 1) {
407 var title = lockscreen.alphaNumeric ?
408 i18n.tr("Sorry, incorrect passphrase.") :
409 i18n.tr("Sorry, incorrect passcode.")
410 var text = i18n.tr("This will be your last attempt.") + " " +
411 (lockscreen.alphaNumeric ?
412 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
413 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
414 lockscreen.showInfoPopup(title, text)
415 } else if (AccountsService.failedLogins >= maxFailedLogins) {
416 SystemImage.factoryReset() // Ouch!
419 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
420 lockscreen.delayMinutes = failedLoginsDelayMinutes
421 forcedDelayTimer.start()
424 lockscreen.clear(true);
425 if (greeter.narrowMode) {
426 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
433 target: LightDM.Greeter
435 value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
441 opacity: greeterWrapper.showProgress * 0.8
445 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
447 objectName: "greeterWrapper"
448 x: greeter.narrowMode ? launcher.progress : 0
451 height: parent.height - panel.panelHeight
454 enabled: !launcher.dashSwipe
458 property bool fullyShown: showProgress === 1.0
459 onFullyShownChanged: {
460 // Wait until the greeter is completely covering lockscreen before resetting it.
461 if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
467 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
468 onShowProgressChanged: {
469 if (showProgress === 0) {
470 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
472 } else if (greeter.narrowMode) {
473 lockscreen.clear(false) // to reset focus if necessary
480 objectName: "greeter"
482 signal sessionStarted() // helpful for tests
484 property string lockedApp: ""
485 property bool hasLockedApp: lockedApp !== ""
488 hides: [launcher, panel.indicators]
490 loadContent: required || lockscreen.required // keeps content in memory for quick show()
494 defaultBackground: shell.background
497 height: parent.height
499 dragHandleWidth: shell.edgeSize
501 function startUnlock() {
503 if (!LightDM.Greeter.authenticated) {
515 if (LightDM.Greeter.startSessionSync()) {
526 if (greeter.narrowMode) {
527 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
531 greeter.lockedApp = "";
532 greeter.forceActiveFocus();
536 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
537 Component.onCompleted: {
538 Connectivity.unlockAllModems()
541 onUnlocked: greeter.hide()
543 // Update launcher items for new user
544 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
545 AccountsService.user = user;
546 LauncherModel.setUser(user);
549 onTease: launcher.tease()
552 target: ApplicationManager
553 property: "suspended"
554 value: greeter.shown && greeterWrapper.showProgress == 1
564 if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
570 function showHome() {
571 if (edgeDemo.running) {
575 if (LightDM.Greeter.active) {
576 greeter.startUnlock()
579 var animate = !LightDM.Greeter.active && !stages.shown
580 dash.setCurrentScope("clickscope", animate, false)
581 ApplicationManager.requestFocusApplication("unity8-dash")
584 function showDash() {
585 if (greeter.hasLockedApp || // just in case user gets here
586 (!greeter.narrowMode && shell.locked)) {
595 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
596 ApplicationManager.requestFocusApplication("unity8-dash")
610 anchors.fill: parent //because this draws indicator menus
613 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
614 contentEnabled: edgeDemo.panelContentEnabled
615 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
616 panelHeight: units.gu(3)
619 property bool topmostApplicationIsFullscreen:
620 ApplicationManager.focusedApplicationId &&
621 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
623 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
624 || greeter.hasLockedApp
629 objectName: "launcher"
631 readonly property bool dashSwipe: progress > 0
633 anchors.top: parent.top
634 anchors.bottom: parent.bottom
636 dragAreaWidth: shell.edgeSize
637 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
639 onShowDashHome: showHome()
641 onDashSwipeChanged: {
643 dash.setCurrentScope("clickscope", false, true)
646 onLauncherApplicationSelected: {
647 if (greeter.hasLockedApp) {
648 greeter.startUnlock()
650 if (!edgeDemo.running)
651 shell.activateApplication(appId)
655 panel.indicators.hide()
661 id: modalNotificationBackground
663 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
676 model: NotificationBackend.Model
681 height: parent.height - panel.panelHeight
686 when: overlay.width <= units.gu(60)
687 AnchorChanges { target: notifications; anchors.left: parent.left }
691 when: overlay.width > units.gu(60)
692 AnchorChanges { target: notifications; anchors.left: undefined }
693 PropertyChanges { target: notifications; width: units.gu(38) }
704 shutdownFadeOutRectangle.enabled = true;
705 shutdownFadeOutRectangle.visible = true;
706 shutdownFadeOut.start();
711 id: alphaDisclaimerLabel
712 anchors.centerIn: parent
713 visible: ApplicationManager.fake ? ApplicationManager.fake : false
715 text: "EARLY ALPHA\nNOT READY FOR USE"
718 font.weight: Font.Black
719 horizontalAlignment: Text.AlignHCenter
720 verticalAlignment: Text.AlignVCenter
721 fontSizeMode: Text.Fit
723 scale: Math.min(parent.width, parent.height) / width
728 z: alphaDisclaimerLabel.z + 10
729 paused: Powerd.status === Powerd.Off // Saves power
732 indicators: panel.indicators
737 target: SessionBroadcast
738 onShowHome: showHome()
742 id: shutdownFadeOutRectangle
749 NumberAnimation on opacity {
754 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
755 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