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 target: ApplicationManager
133 property: "dashActive"
134 value: launcher.shown || launcher.dashSwipe
139 // Handle but do not filter out volume keys
140 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
141 Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
144 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
145 dialogs.onPowerKeyPressed();
146 event.accepted = true;
148 event.accepted = false;
153 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
154 dialogs.onPowerKeyReleased();
155 event.accepted = true;
157 event.accepted = false;
166 height: parent.height
167 visible: !ApplicationManager.empty
170 target: ApplicationManager
172 if (appId === "dialer-app") {
173 // Always let the dialer-app through. Either user asked
174 // for an emergency call or accepted an incoming call.
175 setFakeActiveForApp(appId)
176 } else if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
183 onFocusedApplicationIdChanged: {
184 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
187 panel.indicators.hide();
190 onApplicationAdded: {
191 if (greeter.shown && appId != "unity8-dash") {
194 if (appId === "dialer-app") {
195 // Always let the dialer-app through. Either user asked
196 // for an emergency call or accepted an incoming call.
197 setFakeActiveForApp(appId)
204 id: applicationsDisplayLoader
207 source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
210 target: applicationsDisplayLoader.item
211 property: "objectName"
215 target: applicationsDisplayLoader.item
216 property: "dragAreaWidth"
217 value: shell.edgeSize
220 target: applicationsDisplayLoader.item
221 property: "maximizedAppTopMargin"
222 // Not just using panel.panelHeight as that changes depending on the focused app.
223 value: panel.indicators.panelHeight
226 target: applicationsDisplayLoader.item
227 property: "interactive"
228 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
231 target: applicationsDisplayLoader.item
232 property: "spreadEnabled"
233 value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
236 target: applicationsDisplayLoader.item
237 property: "inverseProgress"
238 value: launcher.progress
241 target: applicationsDisplayLoader.item
242 property: "orientation"
243 value: shell.orientation
250 objectName: "inputMethod"
251 anchors { fill: parent; topMargin: panel.panelHeight }
252 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
256 target: SurfaceManager
258 if (surface.type == MirSurfaceItem.InputMethod) {
259 inputMethod.surface = surface;
263 onSurfaceDestroyed: {
264 if (inputMethod.surface == surface) {
265 inputMethod.surface = null;
266 surface.parent = null;
268 if (!surface.parent) {
269 // there's no one displaying it. delete it right away
275 target: SessionManager
277 if (!session.parentSession && !session.application) {
278 // nothing is using it. delete it right away
286 objectName: "lockscreen"
288 readonly property int backgroundTopMargin: -panel.panelHeight
290 hides: [launcher, panel.indicators]
293 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
294 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
298 height: parent.height - panel.panelHeight
299 background: shell.background
300 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
304 onEntered: LightDM.Greeter.respond(passphrase);
305 onCancel: greeter.show()
306 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
308 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
310 Component.onCompleted: {
311 if (greeter.narrowMode) {
312 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
318 target: LightDM.Greeter
320 onShowGreeter: greeter.show()
321 onHideGreeter: greeter.login()
324 if (greeter.narrowMode) {
325 if (isDefaultPrompt) {
326 if (lockscreen.alphaNumeric) {
327 lockscreen.infoText = i18n.tr("Enter your passphrase")
328 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
330 lockscreen.infoText = i18n.tr("Enter your passcode")
331 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
334 lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
335 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
342 onPromptlessChanged: {
343 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
351 onAuthenticationComplete: {
352 if (LightDM.Greeter.authenticated) {
353 AccountsService.failedLogins = 0
355 // Else only penalize user for a failed login if they actually were
356 // prompted for a password. We do this below after the promptless
359 if (LightDM.Greeter.promptless) {
363 if (LightDM.Greeter.authenticated) {
366 AccountsService.failedLogins++
367 if (maxFailedLogins >= 2) { // require at least a warning
368 if (AccountsService.failedLogins === maxFailedLogins - 1) {
369 var title = lockscreen.alphaNumeric ?
370 i18n.tr("Sorry, incorrect passphrase.") :
371 i18n.tr("Sorry, incorrect passcode.")
372 var text = i18n.tr("This will be your last attempt.") + " " +
373 (lockscreen.alphaNumeric ?
374 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
375 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
376 lockscreen.showInfoPopup(title, text)
377 } else if (AccountsService.failedLogins >= maxFailedLogins) {
378 SystemImage.factoryReset() // Ouch!
381 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
382 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
385 lockscreen.clear(true);
386 if (greeter.narrowMode) {
387 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
394 target: LightDM.Greeter
396 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
402 opacity: greeterWrapper.showProgress * 0.8
406 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
411 height: parent.height - panel.panelHeight
414 enabled: !launcher.dashSwipe
418 property bool fullyShown: showProgress === 1.0
419 onFullyShownChanged: {
420 // Wait until the greeter is completely covering lockscreen before resetting it.
421 if (fullyShown && !LightDM.Greeter.authenticated) {
427 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
428 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
432 objectName: "greeter"
434 signal sessionStarted() // helpful for tests
436 property string fakeActiveForApp: ""
439 hides: [launcher, panel.indicators]
441 loadContent: required || lockscreen.required // keeps content in memory for quick show()
443 defaultBackground: shell.background
446 height: parent.height
448 dragHandleWidth: shell.edgeSize
452 if (LightDM.Greeter.startSessionSync()) {
463 if (greeter.narrowMode) {
464 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
466 greeter.fakeActiveForApp = "";
467 greeter.forceActiveFocus();
471 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
472 Component.onCompleted: {
473 Connectivity.unlockAllModems()
476 onUnlocked: greeter.hide()
478 // Update launcher items for new user
479 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
480 AccountsService.user = user;
481 LauncherModel.setUser(user);
484 onTease: launcher.tease()
487 target: ApplicationManager
488 property: "suspended"
489 value: greeter.shown && greeterWrapper.showProgress == 1
499 if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
505 function showHome() {
506 if (edgeDemo.running) {
510 if (LightDM.Greeter.active) {
511 if (!LightDM.Greeter.authenticated) {
517 var animate = !LightDM.Greeter.active && !stages.shown
518 dash.setCurrentScope("clickscope", animate, false)
519 ApplicationManager.requestFocusApplication("unity8-dash")
522 function showDash() {
531 ApplicationManager.requestFocusApplication("unity8-dash")
544 anchors.fill: parent //because this draws indicator menus
547 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && greeter.fakeActiveForApp === ""
548 contentEnabled: edgeDemo.panelContentEnabled
549 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
550 panelHeight: units.gu(3)
553 property bool topmostApplicationIsFullscreen:
554 ApplicationManager.focusedApplicationId &&
555 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
557 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
558 || greeter.fakeActiveForApp !== ""
563 objectName: "launcher"
565 readonly property bool dashSwipe: progress > 0
567 anchors.top: parent.top
568 anchors.bottom: parent.bottom
570 dragAreaWidth: shell.edgeSize
571 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && greeter.fakeActiveForApp === ""
573 onShowDashHome: showHome()
575 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
583 onDashSwipeChanged: {
585 dash.setCurrentScope("clickscope", false, true)
588 onLauncherApplicationSelected: {
589 if (greeter.fakeActiveForApp !== "") {
592 if (!edgeDemo.running)
593 shell.activateApplication(appId)
597 panel.indicators.hide()
603 id: modalNotificationBackground
605 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
618 model: NotificationBackend.Model
623 height: parent.height - panel.panelHeight
628 when: overlay.width <= units.gu(60)
629 AnchorChanges { target: notifications; anchors.left: parent.left }
633 when: overlay.width > units.gu(60)
634 AnchorChanges { target: notifications; anchors.left: undefined }
635 PropertyChanges { target: notifications; width: units.gu(38) }
646 shutdownFadeOutRectangle.enabled = true;
647 shutdownFadeOutRectangle.visible = true;
648 shutdownFadeOut.start();
653 id: alphaDisclaimerLabel
654 anchors.centerIn: parent
655 visible: ApplicationManager.fake ? ApplicationManager.fake : false
657 text: "EARLY ALPHA\nNOT READY FOR USE"
660 font.weight: Font.Black
661 horizontalAlignment: Text.AlignHCenter
662 verticalAlignment: Text.AlignVCenter
663 fontSizeMode: Text.Fit
665 scale: Math.min(parent.width, parent.height) / width
670 z: alphaDisclaimerLabel.z + 10
671 paused: Powerd.status === Powerd.Off // Saves power
674 indicators: panel.indicators
679 target: SessionBroadcast
680 onShowHome: showHome()
684 id: shutdownFadeOutRectangle
691 NumberAnimation on opacity {
696 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
697 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