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 failedLoginsDelaySeconds: 5 * 60 // seconds 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 setFakeActiveForApp(app) {
92 greeter.fakeActiveForApp = 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 // Handle but do not filter out volume keys
133 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
134 Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
137 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
138 dialogs.onPowerKeyPressed();
139 event.accepted = true;
141 event.accepted = false;
146 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
147 dialogs.onPowerKeyReleased();
148 event.accepted = true;
150 event.accepted = false;
159 height: parent.height
160 visible: !ApplicationManager.empty
163 target: ApplicationManager
165 if (appId === "dialer-app") {
166 // Always let the dialer-app through. Either user asked
167 // for an emergency call or accepted an incoming call.
168 setFakeActiveForApp(appId)
169 } else if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
176 onFocusedApplicationIdChanged: {
177 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
180 panel.indicators.hide();
183 onApplicationAdded: {
184 if (greeter.shown && appId != "unity8-dash") {
187 if (appId === "dialer-app") {
188 // Always let the dialer-app through. Either user asked
189 // for an emergency call or accepted an incoming call.
190 setFakeActiveForApp(appId)
197 id: applicationsDisplayLoader
200 source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
203 target: applicationsDisplayLoader.item
204 property: "objectName"
208 target: applicationsDisplayLoader.item
209 property: "dragAreaWidth"
210 value: shell.edgeSize
213 target: applicationsDisplayLoader.item
214 property: "maximizedAppTopMargin"
215 // Not just using panel.panelHeight as that changes depending on the focused app.
216 value: panel.indicators.panelHeight
219 target: applicationsDisplayLoader.item
220 property: "interactive"
221 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
224 target: applicationsDisplayLoader.item
225 property: "spreadEnabled"
226 value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
229 target: applicationsDisplayLoader.item
230 property: "inverseProgress"
231 value: launcher.progress
234 target: applicationsDisplayLoader.item
235 property: "orientation"
236 value: shell.orientation
243 objectName: "inputMethod"
244 anchors { fill: parent; topMargin: panel.panelHeight }
245 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
249 target: SurfaceManager
251 if (surface.type == MirSurfaceItem.InputMethod) {
252 inputMethod.surface = surface;
256 onSurfaceDestroyed: {
257 if (inputMethod.surface == surface) {
258 inputMethod.surface = null;
259 surface.parent = null;
261 if (!surface.parent) {
262 // there's no one displaying it. delete it right away
268 target: SessionManager
270 if (!session.parentSession && !session.application) {
271 // nothing is using it. delete it right away
279 objectName: "lockscreen"
281 readonly property int backgroundTopMargin: -panel.panelHeight
283 hides: [launcher, panel.indicators]
286 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
287 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
291 height: parent.height - panel.panelHeight
292 background: shell.background
293 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
297 // FIXME: We *should* show emergency dialer if there is a SIM present,
298 // regardless of whether the side stage is enabled. But right now,
299 // the assumption is that narrow screens are phones which have SIMs
300 // and wider screens are tablets which don't. When we do allow this
301 // on devices with a side stage and a SIM, work should be done to
302 // ensure that the main stage is disabled while the dialer is present
303 // in the side stage.
304 showEmergencyCallButton: !shell.sideStageEnabled
306 onEntered: LightDM.Greeter.respond(passphrase);
307 onCancel: greeter.show()
308 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
310 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
312 Component.onCompleted: {
313 if (greeter.narrowMode) {
314 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
320 target: LightDM.Greeter
322 onShowGreeter: greeter.show()
323 onHideGreeter: greeter.login()
326 if (greeter.narrowMode) {
327 if (isDefaultPrompt) {
328 if (lockscreen.alphaNumeric) {
329 lockscreen.infoText = i18n.tr("Enter your passphrase")
330 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
332 lockscreen.infoText = i18n.tr("Enter your passcode")
333 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
336 lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
337 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
344 onPromptlessChanged: {
345 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
353 onAuthenticationComplete: {
354 if (LightDM.Greeter.authenticated) {
355 AccountsService.failedLogins = 0
357 // Else only penalize user for a failed login if they actually were
358 // prompted for a password. We do this below after the promptless
361 if (LightDM.Greeter.promptless) {
365 if (LightDM.Greeter.authenticated) {
368 AccountsService.failedLogins++
369 if (maxFailedLogins >= 2) { // require at least a warning
370 if (AccountsService.failedLogins === maxFailedLogins - 1) {
371 var title = lockscreen.alphaNumeric ?
372 i18n.tr("Sorry, incorrect passphrase.") :
373 i18n.tr("Sorry, incorrect passcode.")
374 var text = i18n.tr("This will be your last attempt.") + " " +
375 (lockscreen.alphaNumeric ?
376 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
377 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
378 lockscreen.showInfoPopup(title, text)
379 } else if (AccountsService.failedLogins >= maxFailedLogins) {
380 SystemImage.factoryReset() // Ouch!
383 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
384 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
387 lockscreen.clear(true);
388 if (greeter.narrowMode) {
389 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
396 target: LightDM.Greeter
398 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
404 opacity: greeterWrapper.showProgress * 0.8
408 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
413 height: parent.height - panel.panelHeight
416 enabled: !launcher.dashSwipe
420 property bool fullyShown: showProgress === 1.0
421 onFullyShownChanged: {
422 // Wait until the greeter is completely covering lockscreen before resetting it.
423 if (fullyShown && !LightDM.Greeter.authenticated) {
429 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
430 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
434 objectName: "greeter"
436 signal sessionStarted() // helpful for tests
438 property string fakeActiveForApp: ""
441 hides: [launcher, panel.indicators]
443 loadContent: required || lockscreen.required // keeps content in memory for quick show()
445 defaultBackground: shell.background
448 height: parent.height
450 dragHandleWidth: shell.edgeSize
454 if (LightDM.Greeter.startSessionSync()) {
465 if (greeter.narrowMode) {
466 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
468 greeter.fakeActiveForApp = "";
469 greeter.forceActiveFocus();
473 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
474 Component.onCompleted: {
475 Connectivity.unlockAllModems()
478 onUnlocked: greeter.hide()
480 // Update launcher items for new user
481 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
482 AccountsService.user = user;
483 LauncherModel.setUser(user);
486 onTease: launcher.tease()
489 target: ApplicationManager
490 property: "suspended"
491 value: greeter.shown && greeterWrapper.showProgress == 1
501 if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
507 function showHome() {
508 if (edgeDemo.running) {
512 if (LightDM.Greeter.active) {
513 if (!LightDM.Greeter.authenticated) {
519 var animate = !LightDM.Greeter.active && !stages.shown
520 dash.setCurrentScope("clickscope", animate, false)
521 ApplicationManager.requestFocusApplication("unity8-dash")
524 function showDash() {
533 ApplicationManager.requestFocusApplication("unity8-dash")
546 anchors.fill: parent //because this draws indicator menus
549 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && greeter.fakeActiveForApp === ""
550 contentEnabled: edgeDemo.panelContentEnabled
551 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
552 panelHeight: units.gu(3)
555 property bool topmostApplicationIsFullscreen:
556 ApplicationManager.focusedApplicationId &&
557 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
559 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
560 || greeter.fakeActiveForApp !== ""
565 objectName: "launcher"
567 readonly property bool dashSwipe: progress > 0
569 anchors.top: parent.top
570 anchors.bottom: parent.bottom
572 dragAreaWidth: shell.edgeSize
573 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && greeter.fakeActiveForApp === ""
575 onShowDashHome: showHome()
577 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
581 onDashSwipeChanged: {
583 dash.setCurrentScope("clickscope", false, true)
586 onLauncherApplicationSelected: {
587 if (greeter.fakeActiveForApp !== "") {
590 if (!edgeDemo.running)
591 shell.activateApplication(appId)
595 panel.indicators.hide()
601 id: modalNotificationBackground
603 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
616 model: NotificationBackend.Model
621 height: parent.height - panel.panelHeight
626 when: overlay.width <= units.gu(60)
627 AnchorChanges { target: notifications; anchors.left: parent.left }
631 when: overlay.width > units.gu(60)
632 AnchorChanges { target: notifications; anchors.left: undefined }
633 PropertyChanges { target: notifications; width: units.gu(38) }
644 shutdownFadeOutRectangle.enabled = true;
645 shutdownFadeOutRectangle.visible = true;
646 shutdownFadeOut.start();
651 id: alphaDisclaimerLabel
652 anchors.centerIn: parent
653 visible: ApplicationManager.fake ? ApplicationManager.fake : false
655 text: "EARLY ALPHA\nNOT READY FOR USE"
658 font.weight: Font.Black
659 horizontalAlignment: Text.AlignHCenter
660 verticalAlignment: Text.AlignVCenter
661 fontSizeMode: Text.Fit
663 scale: Math.min(parent.width, parent.height) / width
668 z: alphaDisclaimerLabel.z + 10
669 paused: Powerd.status === Powerd.Off // Saves power
672 indicators: panel.indicators
677 target: SessionBroadcast
678 onShowHome: showHome()
682 id: shutdownFadeOutRectangle
689 NumberAnimation on opacity {
694 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
695 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