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 "Panel/Indicators"
40import Unity.Notifications 1.0 as NotificationBackend
41import Unity.Session 0.1
42import Unity.DashCommunicator 0.1
47 // this is only here to select the width / height of the window if not running fullscreen
48 property bool tablet: false
49 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
50 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
52 property real edgeSize: units.gu(2)
53 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
54 property url background
55 readonly property real panelHeight: panel.panelHeight
57 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock
58 readonly property bool forcedUnlock: edgeDemo.running
59 onForcedUnlockChanged: if (forcedUnlock) lockscreen.hide()
61 property bool sideStageEnabled: shell.width >= units.gu(100)
62 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
64 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
65 property int failedLoginsDelayAttempts: 7 // number of failed logins
66 property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
68 property int orientation
69 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
70 onDeviceOrientationAngleChanged: {
71 if (!OrientationLock.enabled) {
72 orientation = Screen.orientation;
75 readonly property bool orientationLockEnabled: OrientationLock.enabled
76 onOrientationLockEnabledChanged: {
77 if (orientationLockEnabled) {
78 OrientationLock.savedOrientation = Screen.orientation;
80 orientation = Screen.orientation;
84 function activateApplication(appId) {
85 if (ApplicationManager.findApplication(appId)) {
86 ApplicationManager.requestFocusApplication(appId);
88 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
89 ApplicationManager.startApplication(appId, execFlags);
93 function startLockedApp(app) {
95 console.warn("Called startLockedApp(%1) when not locked, ignoring".arg(app))
98 greeter.lockedApp = app
99 shell.activateApplication(app)
103 target: LauncherModel
104 property: "applicationManager"
105 value: ApplicationManager
108 Component.onCompleted: {
109 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
110 if (ApplicationManager.count > 0) {
111 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
113 if (orientationLockEnabled) {
114 orientation = OrientationLock.savedOrientation;
119 id: backgroundSettings
120 schema.id: "org.gnome.desktop.background"
122 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
123 onGSettingsPictureChanged: {
124 shell.background = gSettingsPicture
133 objectName: "dashCommunicator"
139 enabled: Powerd.status === Powerd.On
143 target: ApplicationManager
144 property: "forceDashActive"
145 value: launcher.shown || launcher.dashSwipe
150 onVolumeDownPressed: volumeControl.volumeDown()
151 onVolumeUpPressed: volumeControl.volumeUp()
152 onBothVolumeKeysPressed: screenGrabber.capture()
157 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
158 dialogs.onPowerKeyPressed();
159 event.accepted = true;
161 volumeKeyFilter.onKeyPressed(event.key);
162 event.accepted = false;
167 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
168 dialogs.onPowerKeyReleased();
169 event.accepted = true;
171 volumeKeyFilter.onKeyReleased(event.key);
172 event.accepted = false;
181 height: parent.height
182 visible: !ApplicationManager.empty
185 target: ApplicationManager
187 if (greeter.narrowMode) {
188 if (appId === "dialer-app" && callManager.hasCalls && shell.locked) {
189 // If we are in the middle of a call, make dialer lockedApp and show it.
190 // This can happen if user backs out of dialer back to greeter, then
191 // launches dialer again.
192 greeter.lockedApp = appId;
194 if (greeter.hasLockedApp) {
195 if (appId === greeter.lockedApp) {
196 lockscreen.hide() // show locked app
198 greeter.startUnlock() // show lockscreen if necessary
203 if (LightDM.Greeter.active) {
204 greeter.startUnlock()
209 onFocusedApplicationIdChanged: {
210 if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
211 greeter.startUnlock()
213 panel.indicators.hide();
216 onApplicationAdded: {
217 if (greeter.shown && appId != "unity8-dash") {
218 greeter.startUnlock()
220 if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
221 lockscreen.hide() // show locked app
228 id: applicationsDisplayLoader
229 objectName: "applicationsDisplayLoader"
232 // When we have a locked app, we only want to show that one app.
233 // FIXME: do this in a less traumatic way. We currently only allow
234 // locked apps in phone mode (see FIXME in Lockscreen component in
235 // this same file). When that changes, we need to do something
236 // nicer here. But this code is currently just to prevent a
237 // theoretical attack where user enters lockedApp mode, then makes
238 // the screen larger (maybe connects to monitor) and tries to enter
240 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
241 source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
244 target: applicationsDisplayLoader.item
245 property: "objectName"
249 target: applicationsDisplayLoader.item
250 property: "dragAreaWidth"
251 value: shell.edgeSize
254 target: applicationsDisplayLoader.item
255 property: "maximizedAppTopMargin"
256 // Not just using panel.panelHeight as that changes depending on the focused app.
257 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
260 target: applicationsDisplayLoader.item
261 property: "interactive"
262 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0 && !notifications.useModal
265 target: applicationsDisplayLoader.item
266 property: "spreadEnabled"
267 value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
270 target: applicationsDisplayLoader.item
271 property: "inverseProgress"
272 value: launcher.progress
275 target: applicationsDisplayLoader.item
276 property: "orientation"
277 value: shell.orientation
284 objectName: "inputMethod"
285 anchors { fill: parent; topMargin: panel.panelHeight }
286 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
290 target: SurfaceManager
292 if (surface.type == MirSurfaceItem.InputMethod) {
293 inputMethod.surface = surface;
297 onSurfaceDestroyed: {
298 if (inputMethod.surface == surface) {
299 inputMethod.surface = null;
300 surface.parent = null;
302 if (!surface.parent) {
303 // there's no one displaying it. delete it right away
309 target: SessionManager
311 if (!session.parentSession && !session.application) {
312 // nothing is using it. delete it right away
320 objectName: "lockscreen"
322 hides: [launcher, panel.indicators]
325 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
326 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
330 height: parent.height - panel.panelHeight
331 background: shell.background
332 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
336 // FIXME: We *should* show emergency dialer if there is a SIM present,
337 // regardless of whether the side stage is enabled. But right now,
338 // the assumption is that narrow screens are phones which have SIMs
339 // and wider screens are tablets which don't. When we do allow this
340 // on devices with a side stage and a SIM, work should be done to
341 // ensure that the main stage is disabled while the dialer is present
342 // in the side stage. See the FIXME in the stage loader in this file.
343 showEmergencyCallButton: !shell.sideStageEnabled
345 onEntered: LightDM.Greeter.respond(passphrase);
346 onCancel: greeter.show()
347 onEmergencyCall: startLockedApp("dialer-app")
349 onShownChanged: if (shown) greeter.lockedApp = ""
351 function maybeShow() {
352 if (!shell.forcedUnlock) {
361 if (lockscreen.delayMinutes > 0) {
362 lockscreen.delayMinutes -= 1
363 if (lockscreen.delayMinutes > 0) {
370 Component.onCompleted: {
371 if (greeter.narrowMode) {
372 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
378 target: LightDM.Greeter
380 onShowGreeter: greeter.show()
381 onHideGreeter: greeter.login()
384 shell.enabled = true;
385 if (!LightDM.Greeter.active) {
386 return; // could happen if hideGreeter() comes in before we prompt
388 if (greeter.narrowMode) {
389 if (isDefaultPrompt) {
390 if (lockscreen.alphaNumeric) {
391 lockscreen.infoText = i18n.tr("Enter passphrase")
392 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase") + "\n" +
393 i18n.tr("Please re-enter")
395 lockscreen.infoText = i18n.tr("Enter passcode")
396 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
399 lockscreen.infoText = i18n.tr("Enter %1").arg(text.toLowerCase())
400 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
403 lockscreen.maybeShow();
407 onPromptlessChanged: {
408 if (!LightDM.Greeter.active) {
409 return; // could happen if hideGreeter() comes in before we prompt
411 if (greeter.narrowMode) {
412 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
416 lockscreen.maybeShow();
421 onAuthenticationComplete: {
422 shell.enabled = true;
423 if (LightDM.Greeter.authenticated) {
424 AccountsService.failedLogins = 0
426 // Else only penalize user for a failed login if they actually were
427 // prompted for a password. We do this below after the promptless
430 if (LightDM.Greeter.promptless) {
434 if (LightDM.Greeter.authenticated) {
437 AccountsService.failedLogins++
438 if (maxFailedLogins >= 2) { // require at least a warning
439 if (AccountsService.failedLogins === maxFailedLogins - 1) {
440 var title = lockscreen.alphaNumeric ?
441 i18n.tr("Sorry, incorrect passphrase.") :
442 i18n.tr("Sorry, incorrect passcode.")
443 var text = i18n.tr("This will be your last attempt.") + " " +
444 (lockscreen.alphaNumeric ?
445 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
446 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
447 lockscreen.showInfoPopup(title, text)
448 } else if (AccountsService.failedLogins >= maxFailedLogins) {
449 SystemImage.factoryReset() // Ouch!
452 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
453 lockscreen.delayMinutes = failedLoginsDelayMinutes
454 forcedDelayTimer.start()
457 lockscreen.clear(true);
458 if (greeter.narrowMode) {
459 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
466 target: LightDM.Greeter
468 value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
474 opacity: greeterWrapper.showProgress * 0.8
478 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
480 objectName: "greeterWrapper"
481 x: greeter.narrowMode ? launcher.progress : 0
484 height: parent.height - panel.panelHeight
487 enabled: !launcher.dashSwipe
491 property bool fullyShown: showProgress === 1.0
492 onFullyShownChanged: {
493 // Wait until the greeter is completely covering lockscreen before resetting it.
494 if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
496 lockscreen.maybeShow();
500 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
501 onShowProgressChanged: {
502 if (showProgress === 0) {
503 if ((LightDM.Greeter.promptless && LightDM.Greeter.authenticated) || shell.forcedUnlock) {
505 } else if (greeter.narrowMode) {
506 lockscreen.clear(false) // to reset focus if necessary
513 objectName: "greeter"
515 signal sessionStarted() // helpful for tests
517 property string lockedApp: ""
518 property bool hasLockedApp: lockedApp !== ""
521 hides: [launcher, panel.indicators]
523 loadContent: required || lockscreen.required // keeps content in memory for quick show()
527 defaultBackground: shell.background
530 height: parent.height
532 dragHandleWidth: shell.edgeSize
534 function startUnlock() {
536 if (!LightDM.Greeter.authenticated) {
537 lockscreen.maybeShow()
548 if (LightDM.Greeter.startSessionSync()) {
559 // Disable everything so that user can't swipe greeter or
560 // launcher until we get first prompt/authenticate, which
561 // will re-enable the shell.
562 shell.enabled = false;
564 if (greeter.narrowMode) {
565 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
569 greeter.lockedApp = "";
570 greeter.forceActiveFocus();
574 Component.onCompleted: {
575 Connectivity.unlockAllModems()
578 onUnlocked: greeter.hide()
580 // Update launcher items for new user
581 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
582 AccountsService.user = user;
583 LauncherModel.setUser(user);
586 onTease: launcher.tease()
589 target: ApplicationManager
590 property: "suspended"
591 value: greeter.shown && greeterWrapper.showProgress == 1
601 if (shell.locked && callManager.hasCalls) {
602 // We just received an incoming call while locked. The
603 // indicator will have already launched dialer-app for us, but
604 // there is a race between "hasCalls" changing and the dialer
605 // starting up. So in case we lose that race, we'll start/
606 // focus the dialer ourselves here too. Even if the indicator
607 // didn't launch the dialer for some reason (or maybe a call
608 // started via some other means), if an active call is
609 // happening, we want to be in the dialer.
610 startLockedApp("dialer-app")
620 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
621 !callManager.hasCalls && !edgeDemo.running) {
627 function showHome() {
628 if (edgeDemo.running) {
632 if (LightDM.Greeter.active) {
633 greeter.startUnlock()
636 var animate = !LightDM.Greeter.active && !stages.shown
637 dash.setCurrentScope(0, animate, false)
638 ApplicationManager.requestFocusApplication("unity8-dash")
641 function showDash() {
642 if (greeter.hasLockedApp || // just in case user gets here
643 (!greeter.narrowMode && shell.locked)) {
652 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
653 ApplicationManager.requestFocusApplication("unity8-dash")
667 anchors.fill: parent //because this draws indicator menus
670 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
671 contentEnabled: edgeDemo.panelContentEnabled
672 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
674 minimizedPanelHeight: units.gu(3)
675 expandedPanelHeight: units.gu(7)
677 indicatorsModel: visibleIndicators.model
681 id: visibleIndicators
682 // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
683 Component.onCompleted: initialise(indicatorProfile)
686 greeterShown: greeter.shown || lockscreen.shown
689 property bool topmostApplicationIsFullscreen:
690 ApplicationManager.focusedApplicationId &&
691 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
693 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
694 || greeter.hasLockedApp
699 objectName: "launcher"
701 readonly property bool dashSwipe: progress > 0
703 anchors.top: parent.top
704 anchors.bottom: parent.bottom
706 dragAreaWidth: shell.edgeSize
707 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
709 onShowDashHome: showHome()
711 onDashSwipeChanged: {
713 dash.setCurrentScope(0, false, true)
716 onLauncherApplicationSelected: {
717 if (greeter.hasLockedApp) {
718 greeter.startUnlock()
720 if (!edgeDemo.running)
721 shell.activateApplication(appId)
725 panel.indicators.hide()
731 id: modalNotificationBackground
733 visible: notifications.useModal && (notifications.state == "narrow")
746 model: NotificationBackend.Model
749 y: topmostIsFullscreen ? 0 : panel.panelHeight
751 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
756 when: overlay.width <= units.gu(60)
757 AnchorChanges { target: notifications; anchors.left: parent.left }
761 when: overlay.width > units.gu(60)
762 AnchorChanges { target: notifications; anchors.left: undefined }
763 PropertyChanges { target: notifications; width: units.gu(38) }
774 shutdownFadeOutRectangle.enabled = true;
775 shutdownFadeOutRectangle.visible = true;
776 shutdownFadeOut.start();
781 id: alphaDisclaimerLabel
782 anchors.centerIn: parent
783 visible: ApplicationManager.fake ? ApplicationManager.fake : false
785 text: "EARLY ALPHA\nNOT READY FOR USE"
788 font.weight: Font.Black
789 horizontalAlignment: Text.AlignHCenter
790 verticalAlignment: Text.AlignVCenter
791 fontSizeMode: Text.Fit
793 scale: Math.min(parent.width, parent.height) / width
798 objectName: "edgeDemo"
799 z: alphaDisclaimerLabel.z + 10
800 paused: Powerd.status === Powerd.Off // Saves power
808 target: SessionBroadcast
809 onShowHome: showHome()
813 id: shutdownFadeOutRectangle
820 NumberAnimation on opacity {
825 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
826 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