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 Unity.Connectivity 0.1
26import Unity.Launcher 0.1
28import LightDM 0.1 as LightDM
30import SessionBroadcast 0.1
37import Unity.Notifications 1.0 as NotificationBackend
38import Unity.Session 0.1
39import Unity.DashCommunicator 0.1
44 // this is only here to select the width / height of the window if not running fullscreen
45 property bool tablet: false
46 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
47 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
49 property real edgeSize: units.gu(2)
50 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
51 property url background
52 readonly property real panelHeight: panel.panelHeight
54 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated
56 property bool sideStageEnabled: shell.width >= units.gu(100)
57 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
59 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
60 property int failedLoginsDelayAttempts: 7 // number of failed logins
61 property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting
63 function activateApplication(appId) {
64 if (ApplicationManager.findApplication(appId)) {
65 ApplicationManager.requestFocusApplication(appId);
67 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
68 ApplicationManager.startApplication(appId, execFlags);
72 function setFakeActiveForApp(app) {
74 greeter.fakeActiveForApp = app
81 property: "applicationManager"
82 value: ApplicationManager
85 Component.onCompleted: {
86 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
90 id: backgroundSettings
91 schema.id: "org.gnome.desktop.background"
93 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
94 onGSettingsPictureChanged: {
95 shell.background = gSettingsPicture
104 objectName: "dashCommunicator"
108 // Handle but do not filter out volume keys
109 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
110 Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
113 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
114 dialogs.onPowerKeyPressed();
115 event.accepted = true;
117 event.accepted = false;
122 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
123 dialogs.onPowerKeyReleased();
124 event.accepted = true;
126 event.accepted = false;
135 height: parent.height
136 visible: !ApplicationManager.empty
139 target: ApplicationManager
141 if (appId === "dialer-app") {
142 // Always let the dialer-app through. Either user asked
143 // for an emergency call or accepted an incoming call.
144 setFakeActiveForApp(appId)
145 } else if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
151 onFocusedApplicationIdChanged: {
152 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
155 panel.indicators.hide();
158 onApplicationAdded: {
159 if (greeter.shown && appId != "unity8-dash") {
162 if (appId === "dialer-app") {
163 // Always let the dialer-app through. Either user asked
164 // for an emergency call or accepted an incoming call.
165 setFakeActiveForApp(appId)
171 id: applicationsDisplayLoader
174 source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
177 target: applicationsDisplayLoader.item
178 property: "objectName"
182 target: applicationsDisplayLoader.item
183 property: "dragAreaWidth"
184 value: shell.edgeSize
187 target: applicationsDisplayLoader.item
188 property: "maximizedAppTopMargin"
189 // Not just using panel.panelHeight as that changes depending on the focused app.
190 value: panel.indicators.panelHeight
193 target: applicationsDisplayLoader.item
194 property: "interactive"
195 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
198 target: applicationsDisplayLoader.item
199 property: "spreadEnabled"
200 value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
203 target: applicationsDisplayLoader.item
204 property: "inverseProgress"
205 value: launcher.progress
212 objectName: "inputMethod"
213 anchors { fill: parent; topMargin: panel.panelHeight }
214 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
218 target: SurfaceManager
220 if (surface.type == MirSurfaceItem.InputMethod) {
221 inputMethod.surface = surface;
225 onSurfaceDestroyed: {
226 if (inputMethod.surface == surface) {
227 inputMethod.surface = null;
228 surface.parent = null;
230 if (!surface.parent) {
231 // there's no one displaying it. delete it right away
237 target: SessionManager
239 if (!session.parentSession && !session.application) {
240 // nothing is using it. delete it right away
248 objectName: "lockscreen"
250 readonly property int backgroundTopMargin: -panel.panelHeight
252 hides: [launcher, panel.indicators]
255 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
256 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
260 height: parent.height - panel.panelHeight
261 background: shell.background
262 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
266 onEntered: LightDM.Greeter.respond(passphrase);
267 onCancel: greeter.show()
268 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
270 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
272 Component.onCompleted: {
273 if (greeter.narrowMode) {
274 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
280 target: LightDM.Greeter
282 onShowGreeter: greeter.show()
283 onHideGreeter: greeter.login()
286 if (greeter.narrowMode) {
287 if (isDefaultPrompt) {
288 if (lockscreen.alphaNumeric) {
289 lockscreen.infoText = i18n.tr("Enter your passphrase")
290 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
292 lockscreen.infoText = i18n.tr("Enter your passcode")
293 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
296 lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
297 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
304 onPromptlessChanged: {
305 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
313 onAuthenticationComplete: {
314 if (LightDM.Greeter.authenticated) {
315 AccountsService.failedLogins = 0
317 // Else only penalize user for a failed login if they actually were
318 // prompted for a password. We do this below after the promptless
321 if (LightDM.Greeter.promptless) {
325 if (LightDM.Greeter.authenticated) {
328 AccountsService.failedLogins++
329 if (maxFailedLogins >= 2) { // require at least a warning
330 if (AccountsService.failedLogins === maxFailedLogins - 1) {
331 var title = lockscreen.alphaNumeric ?
332 i18n.tr("Sorry, incorrect passphrase.") :
333 i18n.tr("Sorry, incorrect passcode.")
334 var text = i18n.tr("This will be your last attempt.") + " " +
335 (lockscreen.alphaNumeric ?
336 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
337 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
338 lockscreen.showInfoPopup(title, text)
339 } else if (AccountsService.failedLogins >= maxFailedLogins) {
340 SystemImage.factoryReset() // Ouch!
343 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
344 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
347 lockscreen.clear(true);
348 if (greeter.narrowMode) {
349 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
356 target: LightDM.Greeter
358 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
364 opacity: greeterWrapper.showProgress * 0.8
368 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
373 height: parent.height - panel.panelHeight
376 enabled: !launcher.dashSwipe
380 property bool fullyShown: showProgress === 1.0
381 onFullyShownChanged: {
382 // Wait until the greeter is completely covering lockscreen before resetting it.
383 if (fullyShown && !LightDM.Greeter.authenticated) {
389 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
390 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
394 objectName: "greeter"
396 signal sessionStarted() // helpful for tests
398 property string fakeActiveForApp: ""
401 hides: [launcher, panel.indicators]
403 loadContent: required || lockscreen.required // keeps content in memory for quick show()
405 defaultBackground: shell.background
408 height: parent.height
410 dragHandleWidth: shell.edgeSize
414 if (LightDM.Greeter.startSessionSync()) {
425 if (greeter.narrowMode) {
426 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
428 greeter.fakeActiveForApp = "";
429 greeter.forceActiveFocus();
433 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
434 Component.onCompleted: {
435 Connectivity.unlockAllModems()
438 onUnlocked: greeter.hide()
440 // Update launcher items for new user
441 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
442 AccountsService.user = user;
443 LauncherModel.setUser(user);
446 onTease: launcher.tease()
449 target: ApplicationManager
450 property: "suspended"
451 value: greeter.shown && greeterWrapper.showProgress == 1
460 onDisplayPowerStateChange: {
461 // We ignore any display-off signals when the proximity sensor
462 // is active. This usually indicates something like a phone call.
463 if (status == Powerd.Off && reason != Powerd.Proximity && !edgeDemo.running) {
467 // No reason to chew demo CPU when user isn't watching
468 if (status == Powerd.Off) {
469 edgeDemo.paused = true;
470 } else if (status == Powerd.On) {
471 edgeDemo.paused = false;
476 function showHome() {
477 if (edgeDemo.running) {
481 if (LightDM.Greeter.active) {
482 if (!LightDM.Greeter.authenticated) {
488 var animate = !LightDM.Greeter.active && !stages.shown
489 dash.setCurrentScope("clickscope", animate, false)
490 ApplicationManager.requestFocusApplication("unity8-dash")
493 function showDash() {
502 ApplicationManager.requestFocusApplication("unity8-dash")
515 anchors.fill: parent //because this draws indicator menus
518 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && greeter.fakeActiveForApp === ""
519 contentEnabled: edgeDemo.panelContentEnabled
520 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
521 panelHeight: units.gu(3)
524 property bool topmostApplicationIsFullscreen:
525 ApplicationManager.focusedApplicationId &&
526 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
528 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
529 || greeter.fakeActiveForApp !== ""
534 objectName: "launcher"
536 readonly property bool dashSwipe: progress > 0
538 anchors.top: parent.top
539 anchors.bottom: parent.bottom
541 dragAreaWidth: shell.edgeSize
542 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && greeter.fakeActiveForApp === ""
544 onShowDashHome: showHome()
546 onDashSwipeChanged: {
547 if (dashSwipe && ApplicationManager.focusedApplicationId !== "unity8-dash") {
548 dash.setCurrentScope("clickscope", false, true)
551 onLauncherApplicationSelected: {
552 if (greeter.fakeActiveForApp !== "") {
555 if (!edgeDemo.running)
556 shell.activateApplication(appId)
560 panel.indicators.hide()
566 id: modalNotificationBackground
568 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
581 model: NotificationBackend.Model
586 height: parent.height - panel.panelHeight
591 when: overlay.width <= units.gu(60)
592 AnchorChanges { target: notifications; anchors.left: parent.left }
596 when: overlay.width > units.gu(60)
597 AnchorChanges { target: notifications; anchors.left: undefined }
598 PropertyChanges { target: notifications; width: units.gu(38) }
615 shutdownFadeOutRectangle.enabled = true;
616 shutdownFadeOutRectangle.visible = true;
617 shutdownFadeOut.start();
622 id: alphaDisclaimerLabel
623 anchors.centerIn: parent
624 visible: ApplicationManager.fake ? ApplicationManager.fake : false
626 text: "EARLY ALPHA\nNOT READY FOR USE"
629 font.weight: Font.Black
630 horizontalAlignment: Text.AlignHCenter
631 verticalAlignment: Text.AlignVCenter
632 fontSizeMode: Text.Fit
634 scale: Math.min(parent.width, parent.height) / width
639 z: alphaDisclaimerLabel.z + 10
642 indicators: panel.indicators
647 target: SessionBroadcast
648 onShowHome: showHome()
652 id: shutdownFadeOutRectangle
659 NumberAnimation on opacity {
664 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
665 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