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 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) {
152 onFocusedApplicationIdChanged: {
153 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
156 panel.indicators.hide();
159 onApplicationAdded: {
160 if (greeter.shown && appId != "unity8-dash") {
163 if (appId === "dialer-app") {
164 // Always let the dialer-app through. Either user asked
165 // for an emergency call or accepted an incoming call.
166 setFakeActiveForApp(appId)
172 id: applicationsDisplayLoader
175 source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
178 target: applicationsDisplayLoader.item
179 property: "objectName"
183 target: applicationsDisplayLoader.item
184 property: "dragAreaWidth"
185 value: shell.edgeSize
188 target: applicationsDisplayLoader.item
189 property: "maximizedAppTopMargin"
190 // Not just using panel.panelHeight as that changes depending on the focused app.
191 value: panel.indicators.panelHeight
194 target: applicationsDisplayLoader.item
195 property: "interactive"
196 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
199 target: applicationsDisplayLoader.item
200 property: "spreadEnabled"
201 value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
204 target: applicationsDisplayLoader.item
205 property: "inverseProgress"
206 value: launcher.progress
213 objectName: "inputMethod"
214 anchors { fill: parent; topMargin: panel.panelHeight }
215 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
219 target: SurfaceManager
221 if (surface.type == MirSurfaceItem.InputMethod) {
222 inputMethod.surface = surface;
226 onSurfaceDestroyed: {
227 if (inputMethod.surface == surface) {
228 inputMethod.surface = null;
229 surface.parent = null;
231 if (!surface.parent) {
232 // there's no one displaying it. delete it right away
240 objectName: "lockscreen"
242 readonly property int backgroundTopMargin: -panel.panelHeight
244 hides: [launcher, panel.indicators]
247 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
248 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
252 height: parent.height - panel.panelHeight
253 background: shell.background
254 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
258 onEntered: LightDM.Greeter.respond(passphrase);
259 onCancel: greeter.show()
260 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
262 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
264 Component.onCompleted: {
265 if (greeter.narrowMode) {
266 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
272 target: LightDM.Greeter
274 onShowGreeter: greeter.show()
277 if (greeter.narrowMode) {
278 if (isDefaultPrompt) {
279 if (lockscreen.alphaNumeric) {
280 lockscreen.infoText = i18n.tr("Enter your passphrase")
281 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
283 lockscreen.infoText = i18n.tr("Enter your PIN")
284 lockscreen.errorText = i18n.tr("Sorry, incorrect PIN")
287 lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
288 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
295 onPromptlessChanged: {
296 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
304 onAuthenticationComplete: {
305 if (LightDM.Greeter.authenticated) {
306 AccountsService.failedLogins = 0
308 // Else only penalize user for a failed login if they actually were
309 // prompted for a password. We do this below after the promptless
312 if (LightDM.Greeter.promptless) {
316 if (LightDM.Greeter.authenticated) {
320 AccountsService.failedLogins++
321 if (maxFailedLogins >= 2) { // require at least a warning
322 if (AccountsService.failedLogins === maxFailedLogins - 1) {
323 var title = lockscreen.alphaNumeric ?
324 i18n.tr("Sorry, incorrect passphrase.") :
325 i18n.tr("Sorry, incorrect passcode.")
326 var text = i18n.tr("This will be your last attempt.") + " " +
327 (lockscreen.alphaNumeric ?
328 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
329 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
330 lockscreen.showInfoPopup(title, text)
331 } else if (AccountsService.failedLogins >= maxFailedLogins) {
332 SystemImage.factoryReset() // Ouch!
335 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
336 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
339 lockscreen.clear(true);
340 if (greeter.narrowMode) {
341 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
348 target: LightDM.Greeter
350 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
356 opacity: greeterWrapper.showProgress * 0.8
360 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
365 height: parent.height - panel.panelHeight
368 enabled: !launcher.dashSwipe
372 property bool fullyShown: showProgress === 1.0
373 onFullyShownChanged: {
374 // Wait until the greeter is completely covering lockscreen before resetting it.
375 if (fullyShown && !LightDM.Greeter.authenticated) {
381 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
382 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
386 objectName: "greeter"
388 signal sessionStarted() // helpful for tests
390 property string fakeActiveForApp: ""
393 hides: [launcher, panel.indicators]
395 loadContent: required || lockscreen.required // keeps content in memory for quick show()
397 defaultBackground: shell.background
400 height: parent.height
402 dragHandleWidth: shell.edgeSize
406 if (LightDM.Greeter.startSessionSync()) {
417 if (greeter.narrowMode) {
418 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
420 greeter.fakeActiveForApp = "";
421 greeter.forceActiveFocus();
425 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
426 Component.onCompleted: {
427 Connectivity.unlockAllModems()
430 onUnlocked: greeter.hide()
432 // Update launcher items for new user
433 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
434 AccountsService.user = user;
435 LauncherModel.setUser(user);
438 onTease: launcher.tease()
441 target: ApplicationManager
442 property: "suspended"
443 value: greeter.shown && greeterWrapper.showProgress == 1
453 if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
459 function showHome() {
460 if (edgeDemo.running) {
464 if (LightDM.Greeter.active) {
465 if (!LightDM.Greeter.authenticated) {
471 var animate = !LightDM.Greeter.active && !stages.shown
472 dash.setCurrentScope("clickscope", animate, false)
473 ApplicationManager.requestFocusApplication("unity8-dash")
476 function showDash() {
485 ApplicationManager.requestFocusApplication("unity8-dash")
498 anchors.fill: parent //because this draws indicator menus
501 available: edgeDemo.panelEnabled && !shell.locked
502 contentEnabled: edgeDemo.panelContentEnabled
503 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
504 panelHeight: units.gu(3)
507 property bool topmostApplicationIsFullscreen:
508 ApplicationManager.focusedApplicationId &&
509 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
511 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
512 || greeter.fakeActiveForApp !== ""
517 objectName: "launcher"
519 readonly property bool dashSwipe: progress > 0
521 anchors.top: parent.top
522 anchors.bottom: parent.bottom
524 dragAreaWidth: shell.edgeSize
525 available: edgeDemo.launcherEnabled && !shell.locked
527 onShowDashHome: showHome()
529 onDashSwipeChanged: {
530 if (dashSwipe && ApplicationManager.focusedApplicationId !== "unity8-dash") {
531 dash.setCurrentScope("clickscope", false, true)
534 onLauncherApplicationSelected: {
535 if (greeter.fakeActiveForApp !== "") {
538 if (!edgeDemo.running)
539 shell.activateApplication(appId)
543 panel.indicators.hide()
549 id: modalNotificationBackground
551 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
564 model: NotificationBackend.Model
569 height: parent.height - panel.panelHeight
574 when: overlay.width <= units.gu(60)
575 AnchorChanges { target: notifications; anchors.left: parent.left }
579 when: overlay.width > units.gu(60)
580 AnchorChanges { target: notifications; anchors.left: undefined }
581 PropertyChanges { target: notifications; width: units.gu(38) }
598 shutdownFadeOutRectangle.enabled = true;
599 shutdownFadeOutRectangle.visible = true;
600 shutdownFadeOut.start();
605 id: alphaDisclaimerLabel
606 anchors.centerIn: parent
607 visible: ApplicationManager.fake ? ApplicationManager.fake : false
609 text: "EARLY ALPHA\nNOT READY FOR USE"
612 font.weight: Font.Black
613 horizontalAlignment: Text.AlignHCenter
614 verticalAlignment: Text.AlignVCenter
615 fontSizeMode: Text.Fit
617 scale: Math.min(parent.width, parent.height) / width
622 z: alphaDisclaimerLabel.z + 10
623 paused: Powerd.status === Powerd.Off // Saves power
626 indicators: panel.indicators
631 target: SessionBroadcast
632 onShowHome: showHome()
636 id: shutdownFadeOutRectangle
643 NumberAnimation on opacity {
648 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
649 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