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
239 objectName: "lockscreen"
241 readonly property int backgroundTopMargin: -panel.panelHeight
243 hides: [launcher, panel.indicators]
246 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
247 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
251 height: parent.height - panel.panelHeight
252 background: shell.background
253 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
257 onEntered: LightDM.Greeter.respond(passphrase);
258 onCancel: greeter.show()
259 onEmergencyCall: shell.activateApplication("dialer-app") // will automatically enter fake-active mode
261 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
263 Component.onCompleted: {
264 if (greeter.narrowMode) {
265 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
271 target: LightDM.Greeter
273 onShowGreeter: greeter.show()
276 if (greeter.narrowMode) {
277 if (isDefaultPrompt) {
278 if (lockscreen.alphaNumeric) {
279 lockscreen.infoText = i18n.tr("Enter your passphrase")
280 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase")
282 lockscreen.infoText = i18n.tr("Enter your PIN")
283 lockscreen.errorText = i18n.tr("Sorry, incorrect PIN")
286 lockscreen.infoText = i18n.tr("Enter your %1").arg(text.toLowerCase())
287 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
294 onPromptlessChanged: {
295 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
303 onAuthenticationComplete: {
304 if (LightDM.Greeter.authenticated) {
305 AccountsService.failedLogins = 0
307 // Else only penalize user for a failed login if they actually were
308 // prompted for a password. We do this below after the promptless
311 if (LightDM.Greeter.promptless) {
315 if (LightDM.Greeter.authenticated) {
319 AccountsService.failedLogins++
320 if (maxFailedLogins >= 2) { // require at least a warning
321 if (AccountsService.failedLogins === maxFailedLogins - 1) {
322 var title = lockscreen.alphaNumeric ?
323 i18n.tr("Sorry, incorrect passphrase.") :
324 i18n.tr("Sorry, incorrect passcode.")
325 var text = i18n.tr("This will be your last attempt.") + " " +
326 (lockscreen.alphaNumeric ?
327 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
328 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
329 lockscreen.showInfoPopup(title, text)
330 } else if (AccountsService.failedLogins >= maxFailedLogins) {
331 SystemImage.factoryReset() // Ouch!
334 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
335 lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
338 lockscreen.clear(true);
339 if (greeter.narrowMode) {
340 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
347 target: LightDM.Greeter
349 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
355 opacity: greeterWrapper.showProgress * 0.8
359 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
364 height: parent.height - panel.panelHeight
367 enabled: !launcher.dashSwipe
371 property bool fullyShown: showProgress === 1.0
372 onFullyShownChanged: {
373 // Wait until the greeter is completely covering lockscreen before resetting it.
374 if (fullyShown && !LightDM.Greeter.authenticated) {
380 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
381 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
385 objectName: "greeter"
387 signal sessionStarted() // helpful for tests
389 property string fakeActiveForApp: ""
392 hides: [launcher, panel.indicators]
394 loadContent: required || lockscreen.required // keeps content in memory for quick show()
396 defaultBackground: shell.background
399 height: parent.height
401 dragHandleWidth: shell.edgeSize
405 if (LightDM.Greeter.startSessionSync()) {
416 if (greeter.narrowMode) {
417 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
419 greeter.fakeActiveForApp = "";
420 greeter.forceActiveFocus();
424 /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
425 Component.onCompleted: {
426 Connectivity.unlockAllModems()
429 onUnlocked: greeter.hide()
431 // Update launcher items for new user
432 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
433 AccountsService.user = user;
434 LauncherModel.setUser(user);
437 onTease: launcher.tease()
440 target: ApplicationManager
441 property: "suspended"
442 value: greeter.shown && greeterWrapper.showProgress == 1
451 onDisplayPowerStateChange: {
452 // We ignore any display-off signals when the proximity sensor
453 // is active. This usually indicates something like a phone call.
454 if (status == Powerd.Off && reason != Powerd.Proximity && !edgeDemo.running) {
458 // No reason to chew demo CPU when user isn't watching
459 if (status == Powerd.Off) {
460 edgeDemo.paused = true;
461 } else if (status == Powerd.On) {
462 edgeDemo.paused = false;
467 function showHome() {
468 if (edgeDemo.running) {
472 if (LightDM.Greeter.active) {
473 if (!LightDM.Greeter.authenticated) {
479 var animate = !LightDM.Greeter.active && !stages.shown
480 dash.setCurrentScope("clickscope", animate, false)
481 ApplicationManager.requestFocusApplication("unity8-dash")
484 function showDash() {
493 ApplicationManager.requestFocusApplication("unity8-dash")
506 anchors.fill: parent //because this draws indicator menus
509 available: edgeDemo.panelEnabled && !shell.locked
510 contentEnabled: edgeDemo.panelContentEnabled
511 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
512 panelHeight: units.gu(3)
515 property bool topmostApplicationIsFullscreen:
516 ApplicationManager.focusedApplicationId &&
517 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
519 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
520 || greeter.fakeActiveForApp !== ""
525 objectName: "launcher"
527 readonly property bool dashSwipe: progress > 0
529 anchors.top: parent.top
530 anchors.bottom: parent.bottom
532 dragAreaWidth: shell.edgeSize
533 available: edgeDemo.launcherEnabled && !shell.locked
535 onShowDashHome: showHome()
537 onDashSwipeChanged: {
538 if (dashSwipe && ApplicationManager.focusedApplicationId !== "unity8-dash") {
539 dash.setCurrentScope("clickscope", false, true)
542 onLauncherApplicationSelected: {
543 if (greeter.fakeActiveForApp !== "") {
546 if (!edgeDemo.running)
547 shell.activateApplication(appId)
551 panel.indicators.hide()
557 id: modalNotificationBackground
559 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
572 model: NotificationBackend.Model
577 height: parent.height - panel.panelHeight
582 when: overlay.width <= units.gu(60)
583 AnchorChanges { target: notifications; anchors.left: parent.left }
587 when: overlay.width > units.gu(60)
588 AnchorChanges { target: notifications; anchors.left: undefined }
589 PropertyChanges { target: notifications; width: units.gu(38) }
606 shutdownFadeOutRectangle.enabled = true;
607 shutdownFadeOutRectangle.visible = true;
608 shutdownFadeOut.start();
613 id: alphaDisclaimerLabel
614 anchors.centerIn: parent
615 visible: ApplicationManager.fake ? ApplicationManager.fake : false
617 text: "EARLY ALPHA\nNOT READY FOR USE"
620 font.weight: Font.Black
621 horizontalAlignment: Text.AlignHCenter
622 verticalAlignment: Text.AlignVCenter
623 fontSizeMode: Text.Fit
625 scale: Math.min(parent.width, parent.height) / width
630 z: alphaDisclaimerLabel.z + 10
633 indicators: panel.indicators
638 target: SessionBroadcast
639 onShowHome: showHome()
643 id: shutdownFadeOutRectangle
650 NumberAnimation on opacity {
655 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
656 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