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.Launcher 0.1
27import LightDM 0.1 as LightDM
29import SessionBroadcast 0.1
36import Unity.Notifications 1.0 as NotificationBackend
37import Unity.Session 0.1
38import Unity.DashCommunicator 0.1
43 // this is only here to select the width / height of the window if not running fullscreen
44 property bool tablet: false
45 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
46 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
48 property real edgeSize: units.gu(2)
49 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
50 property url background
51 readonly property real panelHeight: panel.panelHeight
53 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated
55 property bool sideStageEnabled: shell.width >= units.gu(100)
56 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
58 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
59 property int failedLoginsDelayAttempts: 7 // number of failed logins
60 property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting
62 function activateApplication(appId) {
63 if (ApplicationManager.findApplication(appId)) {
64 ApplicationManager.requestFocusApplication(appId);
66 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
67 ApplicationManager.startApplication(appId, execFlags);
71 function setFakeActiveForApp(app) {
73 greeter.fakeActiveForApp = app
80 property: "applicationManager"
81 value: ApplicationManager
84 Component.onCompleted: {
85 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
89 id: backgroundSettings
90 schema.id: "org.gnome.desktop.background"
92 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
93 onGSettingsPictureChanged: {
94 shell.background = gSettingsPicture
103 objectName: "dashCommunicator"
107 // Handle but do not filter out volume keys
108 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
109 Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
112 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
113 dialogs.onPowerKeyPressed();
114 event.accepted = true;
116 event.accepted = false;
121 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
122 dialogs.onPowerKeyReleased();
123 event.accepted = true;
125 event.accepted = false;
134 height: parent.height
135 visible: !ApplicationManager.empty
138 target: ApplicationManager
140 if (appId === "dialer-app") {
141 // Always let the dialer-app through. Either user asked
142 // for an emergency call or accepted an incoming call.
143 setFakeActiveForApp(appId)
144 } else if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
150 onFocusedApplicationIdChanged: {
151 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
154 panel.indicators.hide();
157 onApplicationAdded: {
158 if (greeter.shown && appId != "unity8-dash") {
161 if (appId === "dialer-app") {
162 // Always let the dialer-app through. Either user asked
163 // for an emergency call or accepted an incoming call.
164 setFakeActiveForApp(appId)
170 id: applicationsDisplayLoader
173 source: shell.sideStageEnabled ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
176 target: applicationsDisplayLoader.item
177 property: "objectName"
181 target: applicationsDisplayLoader.item
182 property: "dragAreaWidth"
183 value: shell.edgeSize
186 target: applicationsDisplayLoader.item
187 property: "maximizedAppTopMargin"
188 // Not just using panel.panelHeight as that changes depending on the focused app.
189 value: panel.indicators.panelHeight
192 target: applicationsDisplayLoader.item
193 property: "interactive"
194 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
197 target: applicationsDisplayLoader.item
198 property: "spreadEnabled"
199 value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
202 target: applicationsDisplayLoader.item
203 property: "inverseProgress"
204 value: launcher.progress
211 objectName: "inputMethod"
212 anchors { fill: parent; topMargin: panel.panelHeight }
213 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
217 target: SurfaceManager
219 if (surface.type == MirSurfaceItem.InputMethod) {
220 inputMethod.surface = surface;
224 onSurfaceDestroyed: {
225 if (inputMethod.surface == surface) {
226 inputMethod.surface = null;
227 surface.parent = null;
229 if (!surface.parent) {
230 // there's no one displaying it. delete it right away
238 objectName: "lockscreen"
240 readonly property int backgroundTopMargin: -panel.panelHeight
242 hides: [launcher, panel.indicators]
245 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
246 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
250 height: parent.height - panel.panelHeight
251 background: shell.background
252 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
256 onEntered: LightDM.Greeter.respond(passphrase);
257 onCancel: greeter.show()
258 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
260 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
262 Component.onCompleted: {
263 if (greeter.narrowMode) {
264 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
270 target: LightDM.Greeter
272 onShowGreeter: greeter.show()
275 if (greeter.narrowMode) {
276 var promptText = text.toLowerCase()
277 if (isDefaultPrompt) {
278 promptText = lockscreen.alphaNumeric ?
279 i18n.tr("passphrase") : i18n.tr("passcode")
281 lockscreen.placeholderText = i18n.tr("Enter your %1").arg(promptText)
282 lockscreen.wrongPlaceholderText = i18n.tr("Incorrect %1").arg(promptText) +
284 i18n.tr("Please re-enter")
289 onPromptlessChanged: {
290 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
298 onAuthenticationComplete: {
299 if (LightDM.Greeter.authenticated) {
300 AccountsService.failedLogins = 0
302 // Else only penalize user for a failed login if they actually were
303 // prompted for a password. We do this below after the promptless
306 if (LightDM.Greeter.promptless) {
310 if (LightDM.Greeter.authenticated) {
314 AccountsService.failedLogins++
315 if (maxFailedLogins >= 2) { // require at least a warning
316 if (AccountsService.failedLogins === maxFailedLogins - 1) {
317 var title = lockscreen.alphaNumeric ?
318 i18n.tr("Sorry, incorrect passphrase.") :
319 i18n.tr("Sorry, incorrect passcode.")
320 var text = i18n.tr("This will be your last attempt.") + " " +
321 (lockscreen.alphaNumeric ?
322 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
323 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
324 lockscreen.showInfoPopup(title, text)
325 } else if (AccountsService.failedLogins >= maxFailedLogins) {
326 SystemImage.factoryReset() // Ouch!
329 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
330 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
333 lockscreen.clear(true);
334 if (greeter.narrowMode) {
335 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
342 target: LightDM.Greeter
344 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
350 opacity: greeterWrapper.showProgress * 0.8
354 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
359 height: parent.height - panel.panelHeight
362 enabled: !launcher.dashSwipe
366 property bool fullyShown: showProgress === 1.0
367 onFullyShownChanged: {
368 // Wait until the greeter is completely covering lockscreen before resetting it.
369 if (fullyShown && !LightDM.Greeter.authenticated) {
375 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
376 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
380 objectName: "greeter"
382 signal sessionStarted() // helpful for tests
384 property string fakeActiveForApp: ""
387 hides: [launcher, panel.indicators]
389 loadContent: required || lockscreen.required // keeps content in memory for quick show()
391 defaultBackground: shell.background
394 height: parent.height
396 dragHandleWidth: shell.edgeSize
400 if (LightDM.Greeter.startSessionSync()) {
411 if (greeter.narrowMode) {
412 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
414 greeter.fakeActiveForApp = "";
415 greeter.forceActiveFocus();
419 onUnlocked: greeter.hide()
421 // Update launcher items for new user
422 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
423 AccountsService.user = user;
424 LauncherModel.setUser(user);
427 onTease: launcher.tease()
430 target: ApplicationManager
431 property: "suspended"
432 value: greeter.shown && greeterWrapper.showProgress == 1
441 onDisplayPowerStateChange: {
442 // We ignore any display-off signals when the proximity sensor
443 // is active. This usually indicates something like a phone call.
444 if (status == Powerd.Off && reason != Powerd.Proximity && !edgeDemo.running) {
448 // No reason to chew demo CPU when user isn't watching
449 if (status == Powerd.Off) {
450 edgeDemo.paused = true;
451 } else if (status == Powerd.On) {
452 edgeDemo.paused = false;
457 function showHome() {
458 if (edgeDemo.running) {
462 if (LightDM.Greeter.active) {
463 if (!LightDM.Greeter.authenticated) {
469 var animate = !LightDM.Greeter.active && !stages.shown
470 dash.setCurrentScope("clickscope", animate, false)
471 ApplicationManager.requestFocusApplication("unity8-dash")
474 function showDash() {
483 ApplicationManager.requestFocusApplication("unity8-dash")
496 anchors.fill: parent //because this draws indicator menus
499 available: edgeDemo.panelEnabled && !shell.locked
500 contentEnabled: edgeDemo.panelContentEnabled
501 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
502 panelHeight: units.gu(3)
505 property bool topmostApplicationIsFullscreen:
506 ApplicationManager.focusedApplicationId &&
507 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
509 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
510 || greeter.fakeActiveForApp !== ""
515 objectName: "launcher"
517 readonly property bool dashSwipe: progress > 0
519 anchors.top: parent.top
520 anchors.bottom: parent.bottom
522 dragAreaWidth: shell.edgeSize
523 available: edgeDemo.launcherEnabled && !shell.locked
525 onShowDashHome: showHome()
527 onDashSwipeChanged: {
528 if (dashSwipe && ApplicationManager.focusedApplicationId !== "unity8-dash") {
529 dash.setCurrentScope("clickscope", false, true)
532 onLauncherApplicationSelected: {
533 if (greeter.fakeActiveForApp !== "") {
536 if (!edgeDemo.running)
537 shell.activateApplication(appId)
541 panel.indicators.hide()
547 id: modalNotificationBackground
549 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
562 model: NotificationBackend.Model
567 height: parent.height - panel.panelHeight
572 when: overlay.width <= units.gu(60)
573 AnchorChanges { target: notifications; anchors.left: parent.left }
577 when: overlay.width > units.gu(60)
578 AnchorChanges { target: notifications; anchors.left: undefined }
579 PropertyChanges { target: notifications; width: units.gu(38) }
596 shutdownFadeOutRectangle.enabled = true;
597 shutdownFadeOutRectangle.visible = true;
598 shutdownFadeOut.start();
603 id: alphaDisclaimerLabel
604 anchors.centerIn: parent
605 visible: ApplicationManager.fake ? ApplicationManager.fake : false
607 text: "EARLY ALPHA\nNOT READY FOR USE"
610 font.weight: Font.Black
611 horizontalAlignment: Text.AlignHCenter
612 verticalAlignment: Text.AlignVCenter
613 fontSizeMode: Text.Fit
615 scale: Math.min(parent.width, parent.height) / width
620 z: alphaDisclaimerLabel.z + 10
623 indicators: panel.indicators
628 target: SessionBroadcast
629 onShowHome: showHome()
633 id: shutdownFadeOutRectangle
640 NumberAnimation on opacity {
645 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
646 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