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
59 property bool sideStageEnabled: shell.width >= units.gu(100)
60 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
62 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
63 property int failedLoginsDelayAttempts: 7 // number of failed logins
64 property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting
66 property int orientation
67 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
68 onDeviceOrientationAngleChanged: {
69 if (!OrientationLock.enabled) {
70 orientation = Screen.orientation;
73 readonly property bool orientationLockEnabled: OrientationLock.enabled
74 onOrientationLockEnabledChanged: {
75 if (orientationLockEnabled) {
76 OrientationLock.savedOrientation = Screen.orientation;
78 orientation = Screen.orientation;
82 function activateApplication(appId) {
83 if (ApplicationManager.findApplication(appId)) {
84 ApplicationManager.requestFocusApplication(appId);
86 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
87 ApplicationManager.startApplication(appId, execFlags);
91 function setFakeActiveForApp(app) {
93 greeter.fakeActiveForApp = app
100 property: "applicationManager"
101 value: ApplicationManager
104 Component.onCompleted: {
105 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
106 if (ApplicationManager.count > 0) {
107 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
109 if (orientationLockEnabled) {
110 orientation = OrientationLock.savedOrientation;
115 id: backgroundSettings
116 schema.id: "org.gnome.desktop.background"
118 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
119 onGSettingsPictureChanged: {
120 shell.background = gSettingsPicture
129 objectName: "dashCommunicator"
133 // Handle but do not filter out volume keys
134 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
135 Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
138 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
139 dialogs.onPowerKeyPressed();
140 event.accepted = true;
142 event.accepted = false;
147 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
148 dialogs.onPowerKeyReleased();
149 event.accepted = true;
151 event.accepted = false;
160 height: parent.height
161 visible: !ApplicationManager.empty
164 target: ApplicationManager
166 if (appId === "dialer-app") {
167 // Always let the dialer-app through. Either user asked
168 // for an emergency call or accepted an incoming call.
169 setFakeActiveForApp(appId)
170 } else if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
177 onFocusedApplicationIdChanged: {
178 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
181 panel.indicators.hide();
184 onApplicationAdded: {
185 if (greeter.shown && appId != "unity8-dash") {
188 if (appId === "dialer-app") {
189 // Always let the dialer-app through. Either user asked
190 // for an emergency call or accepted an incoming call.
191 setFakeActiveForApp(appId)
198 id: applicationsDisplayLoader
201 source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
204 target: applicationsDisplayLoader.item
205 property: "objectName"
209 target: applicationsDisplayLoader.item
210 property: "dragAreaWidth"
211 value: shell.edgeSize
214 target: applicationsDisplayLoader.item
215 property: "maximizedAppTopMargin"
216 // Not just using panel.panelHeight as that changes depending on the focused app.
217 value: panel.indicators.panelHeight
220 target: applicationsDisplayLoader.item
221 property: "interactive"
222 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
225 target: applicationsDisplayLoader.item
226 property: "spreadEnabled"
227 value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
230 target: applicationsDisplayLoader.item
231 property: "inverseProgress"
232 value: launcher.progress
235 target: applicationsDisplayLoader.item
236 property: "orientation"
237 value: shell.orientation
244 objectName: "inputMethod"
245 anchors { fill: parent; topMargin: panel.panelHeight }
246 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
250 target: SurfaceManager
252 if (surface.type == MirSurfaceItem.InputMethod) {
253 inputMethod.surface = surface;
257 onSurfaceDestroyed: {
258 if (inputMethod.surface == surface) {
259 inputMethod.surface = null;
260 surface.parent = null;
262 if (!surface.parent) {
263 // there's no one displaying it. delete it right away
269 target: SessionManager
271 if (!session.parentSession && !session.application) {
272 // nothing is using it. delete it right away
280 objectName: "lockscreen"
282 readonly property int backgroundTopMargin: -panel.panelHeight
284 hides: [launcher, panel.indicators]
287 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
288 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
292 height: parent.height - panel.panelHeight
293 background: shell.background
294 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
298 onEntered: LightDM.Greeter.respond(passphrase);
299 onCancel: greeter.show()
300 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
302 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
304 Component.onCompleted: {
305 if (greeter.narrowMode) {
306 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
312 target: LightDM.Greeter
314 onShowGreeter: greeter.show()
315 onHideGreeter: greeter.login()
318 if (greeter.narrowMode) {
319 if (isDefaultPrompt) {
320 if (lockscreen.alphaNumeric) {
321 lockscreen.infoText = i18n.tr("Enter your passphrase")
322 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
324 lockscreen.infoText = i18n.tr("Enter your passcode")
325 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
328 lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
329 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
336 onPromptlessChanged: {
337 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
345 onAuthenticationComplete: {
346 if (LightDM.Greeter.authenticated) {
347 AccountsService.failedLogins = 0
349 // Else only penalize user for a failed login if they actually were
350 // prompted for a password. We do this below after the promptless
353 if (LightDM.Greeter.promptless) {
357 if (LightDM.Greeter.authenticated) {
360 AccountsService.failedLogins++
361 if (maxFailedLogins >= 2) { // require at least a warning
362 if (AccountsService.failedLogins === maxFailedLogins - 1) {
363 var title = lockscreen.alphaNumeric ?
364 i18n.tr("Sorry, incorrect passphrase.") :
365 i18n.tr("Sorry, incorrect passcode.")
366 var text = i18n.tr("This will be your last attempt.") + " " +
367 (lockscreen.alphaNumeric ?
368 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
369 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
370 lockscreen.showInfoPopup(title, text)
371 } else if (AccountsService.failedLogins >= maxFailedLogins) {
372 SystemImage.factoryReset() // Ouch!
375 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
376 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
379 lockscreen.clear(true);
380 if (greeter.narrowMode) {
381 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
388 target: LightDM.Greeter
390 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
396 opacity: greeterWrapper.showProgress * 0.8
400 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
405 height: parent.height - panel.panelHeight
408 enabled: !launcher.dashSwipe
412 property bool fullyShown: showProgress === 1.0
413 onFullyShownChanged: {
414 // Wait until the greeter is completely covering lockscreen before resetting it.
415 if (fullyShown && !LightDM.Greeter.authenticated) {
421 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
422 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
426 objectName: "greeter"
428 signal sessionStarted() // helpful for tests
430 property string fakeActiveForApp: ""
433 hides: [launcher, panel.indicators]
435 loadContent: required || lockscreen.required // keeps content in memory for quick show()
437 defaultBackground: shell.background
440 height: parent.height
442 dragHandleWidth: shell.edgeSize
446 if (LightDM.Greeter.startSessionSync()) {
457 if (greeter.narrowMode) {
458 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
460 greeter.fakeActiveForApp = "";
461 greeter.forceActiveFocus();
465 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
466 Component.onCompleted: {
467 Connectivity.unlockAllModems()
470 onUnlocked: greeter.hide()
472 // Update launcher items for new user
473 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
474 AccountsService.user = user;
475 LauncherModel.setUser(user);
478 onTease: launcher.tease()
481 target: ApplicationManager
482 property: "suspended"
483 value: greeter.shown && greeterWrapper.showProgress == 1
493 if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
499 function showHome() {
500 if (edgeDemo.running) {
504 if (LightDM.Greeter.active) {
505 if (!LightDM.Greeter.authenticated) {
511 var animate = !LightDM.Greeter.active && !stages.shown
512 dash.setCurrentScope("clickscope", animate, false)
513 ApplicationManager.requestFocusApplication("unity8-dash")
516 function showDash() {
525 ApplicationManager.requestFocusApplication("unity8-dash")
538 anchors.fill: parent //because this draws indicator menus
541 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && greeter.fakeActiveForApp === ""
542 contentEnabled: edgeDemo.panelContentEnabled
543 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
545 minimizedPanelHeight: units.gu(3)
546 expandedPanelHeight: units.gu(7)
548 indicatorsModel: visibleIndicators.model
552 id: visibleIndicators
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") {
585 onDashSwipeChanged: {
587 dash.setCurrentScope("clickscope", false, true)
590 onLauncherApplicationSelected: {
591 if (greeter.fakeActiveForApp !== "") {
594 if (!edgeDemo.running)
595 shell.activateApplication(appId)
599 panel.indicators.hide()
605 id: modalNotificationBackground
607 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
620 model: NotificationBackend.Model
625 height: parent.height - panel.panelHeight
630 when: overlay.width <= units.gu(60)
631 AnchorChanges { target: notifications; anchors.left: parent.left }
635 when: overlay.width > units.gu(60)
636 AnchorChanges { target: notifications; anchors.left: undefined }
637 PropertyChanges { target: notifications; width: units.gu(38) }
648 shutdownFadeOutRectangle.enabled = true;
649 shutdownFadeOutRectangle.visible = true;
650 shutdownFadeOut.start();
655 id: alphaDisclaimerLabel
656 anchors.centerIn: parent
657 visible: ApplicationManager.fake ? ApplicationManager.fake : false
659 text: "EARLY ALPHA\nNOT READY FOR USE"
662 font.weight: Font.Black
663 horizontalAlignment: Text.AlignHCenter
664 verticalAlignment: Text.AlignVCenter
665 fontSizeMode: Text.Fit
667 scale: Math.min(parent.width, parent.height) / width
672 z: alphaDisclaimerLabel.z + 10
673 paused: Powerd.status === Powerd.Off // Saves power
676 indicators: panel.indicators
681 target: SessionBroadcast
682 onShowHome: showHome()
686 id: shutdownFadeOutRectangle
693 NumberAnimation on opacity {
698 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
699 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