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 failedLoginsDelayMinutes: 5 // minutes 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 setFakeActiveForApp(app) {
75 greeter.fakeActiveForApp = 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.
145 setFakeActiveForApp(appId)
146 } else if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
153 onFocusedApplicationIdChanged: {
154 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== 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.
167 setFakeActiveForApp(appId)
174 id: applicationsDisplayLoader
177 source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
180 target: applicationsDisplayLoader.item
181 property: "objectName"
185 target: applicationsDisplayLoader.item
186 property: "dragAreaWidth"
187 value: shell.edgeSize
190 target: applicationsDisplayLoader.item
191 property: "maximizedAppTopMargin"
192 // Not just using panel.panelHeight as that changes depending on the focused app.
193 value: panel.indicators.panelHeight
196 target: applicationsDisplayLoader.item
197 property: "interactive"
198 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
201 target: applicationsDisplayLoader.item
202 property: "spreadEnabled"
203 value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
206 target: applicationsDisplayLoader.item
207 property: "inverseProgress"
208 value: launcher.progress
215 objectName: "inputMethod"
216 anchors { fill: parent; topMargin: panel.panelHeight }
217 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
221 target: SurfaceManager
223 if (surface.type == MirSurfaceItem.InputMethod) {
224 inputMethod.surface = surface;
228 onSurfaceDestroyed: {
229 if (inputMethod.surface == surface) {
230 inputMethod.surface = null;
231 surface.parent = null;
233 if (!surface.parent) {
234 // there's no one displaying it. delete it right away
240 target: SessionManager
242 if (!session.parentSession && !session.application) {
243 // nothing is using it. delete it right away
251 objectName: "lockscreen"
253 hides: [launcher, panel.indicators]
256 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
257 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
261 height: parent.height - panel.panelHeight
262 background: shell.background
263 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
267 onEntered: LightDM.Greeter.respond(passphrase);
268 onCancel: greeter.show()
269 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
271 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
277 if (lockscreen.delayMinutes > 0) {
278 lockscreen.delayMinutes -= 1
279 if (lockscreen.delayMinutes > 0) {
286 Component.onCompleted: {
287 if (greeter.narrowMode) {
288 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
294 target: LightDM.Greeter
296 onShowGreeter: greeter.show()
297 onHideGreeter: greeter.login()
300 if (greeter.narrowMode) {
301 if (isDefaultPrompt) {
302 if (lockscreen.alphaNumeric) {
303 lockscreen.infoText = i18n.tr("Enter passphrase")
304 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase") + "\n" +
305 i18n.tr("Please re-enter")
307 lockscreen.infoText = i18n.tr("Enter passcode")
308 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
311 lockscreen.infoText = i18n.tr("Enter %1").arg(text.toLowerCase())
312 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
319 onPromptlessChanged: {
320 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
328 onAuthenticationComplete: {
329 if (LightDM.Greeter.authenticated) {
330 AccountsService.failedLogins = 0
332 // Else only penalize user for a failed login if they actually were
333 // prompted for a password. We do this below after the promptless
336 if (LightDM.Greeter.promptless) {
340 if (LightDM.Greeter.authenticated) {
343 AccountsService.failedLogins++
344 if (maxFailedLogins >= 2) { // require at least a warning
345 if (AccountsService.failedLogins === maxFailedLogins - 1) {
346 var title = lockscreen.alphaNumeric ?
347 i18n.tr("Sorry, incorrect passphrase.") :
348 i18n.tr("Sorry, incorrect passcode.")
349 var text = i18n.tr("This will be your last attempt.") + " " +
350 (lockscreen.alphaNumeric ?
351 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
352 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
353 lockscreen.showInfoPopup(title, text)
354 } else if (AccountsService.failedLogins >= maxFailedLogins) {
355 SystemImage.factoryReset() // Ouch!
358 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
359 lockscreen.delayMinutes = failedLoginsDelayMinutes
360 forcedDelayTimer.start()
363 lockscreen.clear(true);
364 if (greeter.narrowMode) {
365 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
372 target: LightDM.Greeter
374 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
380 opacity: greeterWrapper.showProgress * 0.8
384 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
389 height: parent.height - panel.panelHeight
392 enabled: !launcher.dashSwipe
396 property bool fullyShown: showProgress === 1.0
397 onFullyShownChanged: {
398 // Wait until the greeter is completely covering lockscreen before resetting it.
399 if (fullyShown && !LightDM.Greeter.authenticated) {
405 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
406 onShowProgressChanged: {
407 if (showProgress === 0) {
408 if (LightDM.Greeter.authenticated) {
410 } else if (greeter.narrowMode) {
411 lockscreen.clear(false) // to reset focus if necessary
418 objectName: "greeter"
420 signal sessionStarted() // helpful for tests
422 property string fakeActiveForApp: ""
425 hides: [launcher, panel.indicators]
427 loadContent: required || lockscreen.required // keeps content in memory for quick show()
429 defaultBackground: shell.background
432 height: parent.height
434 dragHandleWidth: shell.edgeSize
438 if (LightDM.Greeter.startSessionSync()) {
449 if (greeter.narrowMode) {
450 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
452 greeter.fakeActiveForApp = "";
453 greeter.forceActiveFocus();
457 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
458 Component.onCompleted: {
459 Connectivity.unlockAllModems()
462 onUnlocked: greeter.hide()
464 // Update launcher items for new user
465 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
466 AccountsService.user = user;
467 LauncherModel.setUser(user);
470 onTease: launcher.tease()
473 target: ApplicationManager
474 property: "suspended"
475 value: greeter.shown && greeterWrapper.showProgress == 1
485 if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
491 function showHome() {
492 if (edgeDemo.running) {
496 if (LightDM.Greeter.active) {
497 if (!LightDM.Greeter.authenticated) {
503 var animate = !LightDM.Greeter.active && !stages.shown
504 dash.setCurrentScope("clickscope", animate, false)
505 ApplicationManager.requestFocusApplication("unity8-dash")
508 function showDash() {
517 ApplicationManager.requestFocusApplication("unity8-dash")
530 anchors.fill: parent //because this draws indicator menus
533 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && greeter.fakeActiveForApp === ""
534 contentEnabled: edgeDemo.panelContentEnabled
535 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
536 panelHeight: units.gu(3)
539 property bool topmostApplicationIsFullscreen:
540 ApplicationManager.focusedApplicationId &&
541 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
543 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
544 || greeter.fakeActiveForApp !== ""
549 objectName: "launcher"
551 readonly property bool dashSwipe: progress > 0
553 anchors.top: parent.top
554 anchors.bottom: parent.bottom
556 dragAreaWidth: shell.edgeSize
557 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && greeter.fakeActiveForApp === ""
559 onShowDashHome: showHome()
561 onDashSwipeChanged: {
563 dash.setCurrentScope("clickscope", false, true)
566 onLauncherApplicationSelected: {
567 if (greeter.fakeActiveForApp !== "") {
570 if (!edgeDemo.running)
571 shell.activateApplication(appId)
575 panel.indicators.hide()
581 id: modalNotificationBackground
583 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
596 model: NotificationBackend.Model
601 height: parent.height - panel.panelHeight
606 when: overlay.width <= units.gu(60)
607 AnchorChanges { target: notifications; anchors.left: parent.left }
611 when: overlay.width > units.gu(60)
612 AnchorChanges { target: notifications; anchors.left: undefined }
613 PropertyChanges { target: notifications; width: units.gu(38) }
624 shutdownFadeOutRectangle.enabled = true;
625 shutdownFadeOutRectangle.visible = true;
626 shutdownFadeOut.start();
631 id: alphaDisclaimerLabel
632 anchors.centerIn: parent
633 visible: ApplicationManager.fake ? ApplicationManager.fake : false
635 text: "EARLY ALPHA\nNOT READY FOR USE"
638 font.weight: Font.Black
639 horizontalAlignment: Text.AlignHCenter
640 verticalAlignment: Text.AlignVCenter
641 fontSizeMode: Text.Fit
643 scale: Math.min(parent.width, parent.height) / width
648 z: alphaDisclaimerLabel.z + 10
649 paused: Powerd.status === Powerd.Off // Saves power
652 indicators: panel.indicators
657 target: SessionBroadcast
658 onShowHome: showHome()
662 id: shutdownFadeOutRectangle
669 NumberAnimation on opacity {
674 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
675 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