@@ -21,10 +21,11 @@ import Unity.Application 0.1
2121import Ubuntu.Components 0.1
2222import Ubuntu.Gestures 0.1
2323import Unity.Launcher 0.1
24+import LightDM 0.1 as LightDM
2425import Powerd 0.1
2526import SessionBroadcast 0.1
26−import SessionManager 0.1
2727import "Dash"
28+import "Greeter"
2829import "Launcher"
2930import "Panel"
3031import "Components"
@@ -32,9 +33,17 @@ import "Notifications"
3233import Unity.Notifications 1.0 as NotificationBackend
3334import Unity.Session 0.1
3435
35−BasicShell {
36+FocusScope {
3637 id: shell
3738
39+ // this is only here to select the width / height of the window if not running fullscreen
40+ property bool tablet: false
41+ width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
42+ height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
43+
44+ property real edgeSize: units.gu(2)
45+ property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
46+ property url background
3847 readonly property real panelHeight: panel.panelHeight
3948
4049 property bool dashShown: dash.shown
@@ -70,7 +79,17 @@ BasicShell {
7079 id: backgroundSettings
7180 schema.id: "org.gnome.desktop.background"
7281 }
73− backgroundSource: backgroundSettings.pictureUri
82+ property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
83+ onGSettingsPictureChanged: {
84+ shell.background = gSettingsPicture
85+ }
86+
87+ VolumeControl {
88+ id: volumeControl
89+ }
90+
91+ Keys.onVolumeUpPressed: volumeControl.volumeUp()
92+ Keys.onVolumeDownPressed: volumeControl.volumeDown()
7493
7594 Item {
7695 id: underlayClipper
@@ -117,9 +136,10 @@ BasicShell {
117136 id: dash
118137 objectName: "dash"
119138
139+ available: !greeter.shown && !lockscreen.shown
120140 hides: [stages, launcher, panel.indicators]
121− shown: disappearingAnimationProgress !== 1.0
122− enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
141+ shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
142+ enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
123143
124144 anchors {
125145 fill: parent
@@ -207,6 +227,7 @@ BasicShell {
207227 shown = true;
208228 panel.indicators.hide();
209229 edgeDemo.stopDemo();
230+ greeter.hide();
210231 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
211232 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
212233 }
@@ -271,12 +292,6 @@ BasicShell {
271292 }
272293 }
273294
274− Binding {
275− target: ApplicationManager
276− property: "suspended"
277− value: !SessionManager.active
278− }
279−
280295 Loader {
281296 id: applicationsDisplayLoader
282297 anchors.fill: parent
@@ -301,9 +316,132 @@ BasicShell {
301316 }
302317 }
303318
319+ Lockscreen {
320+ id: lockscreen
321+ objectName: "lockscreen"
322+
323+ readonly property int backgroundTopMargin: -panel.panelHeight
324+
325+ hides: [launcher, panel.indicators]
326+ shown: false
327+ enabled: true
328+ showAnimation: StandardAnimation { property: "opacity"; to: 1 }
329+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
330+ y: panel.panelHeight
331+ x: required ? 0 : - width
332+ width: parent.width
333+ height: parent.height - panel.panelHeight
334+ background: shell.background
335+ minPinLength: 4
336+ maxPinLength: 4
337+
338+ onEntered: LightDM.Greeter.respond(passphrase);
339+ onCancel: greeter.show()
340+
341+ Component.onCompleted: {
342+ if (LightDM.Users.count == 1) {
343+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
344+ }
345+ }
346+ }
347+
348+ Connections {
349+ target: LightDM.Greeter
350+
351+ onShowPrompt: {
352+ if (LightDM.Users.count == 1) {
353+ // TODO: There's no better way for now to determine if its a PIN or a passphrase.
354+ if (text == "PIN") {
355+ lockscreen.alphaNumeric = false
356+ } else {
357+ lockscreen.alphaNumeric = true
358+ }
359+ lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
360+ lockscreen.show();
361+ }
362+ }
363+
364+ onAuthenticationComplete: {
365+ if (LightDM.Greeter.promptless) {
366+ return;
367+ }
368+ if (LightDM.Greeter.authenticated) {
369+ lockscreen.hide();
370+ } else {
371+ lockscreen.clear(true);
372+ }
373+ }
374+ }
375+
376+ Rectangle {
377+ anchors.fill: parent
378+ color: "black"
379+ opacity: greeterWrapper.showProgress * 0.8
380+ }
381+
382+ Item {
383+ // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
384+ id: greeterWrapper
385+ x: launcher.progress
386+ y: panel.panelHeight
387+ width: parent.width
388+ height: parent.height - panel.panelHeight
389+
390+ Behavior on x {
391+ enabled: !launcher.dashSwipe
392+ StandardAnimation {}
393+ }
394+
395+ readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
396+
397+ Greeter {
398+ id: greeter
399+ objectName: "greeter"
400+
401+ available: true
402+ hides: [launcher, panel.indicators]
403+ shown: true
404+
405+ defaultBackground: shell.background
406+
407+ width: parent.width
408+ height: parent.height
409+
410+ dragHandleWidth: shell.edgeSize
411+
412+ onShownChanged: {
413+ if (shown) {
414+ lockscreen.reset();
415+ // If there is only one user, we start authenticating with that one here.
416+ // If there are more users, the Greeter will handle that
417+ if (LightDM.Users.count == 1) {
418+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
419+ }
420+ greeter.forceActiveFocus();
421+ }
422+ }
423+
424+ onUnlocked: greeter.hide()
425+ onSelected: {
426+ // Update launcher items for new user
427+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
428+ AccountsService.user = user;
429+ LauncherModel.setUser(user);
430+ }
431+
432+ onTease: launcher.tease()
433+
434+ Binding {
435+ target: ApplicationManager
436+ property: "suspended"
437+ value: greeter.shown && greeterWrapper.showProgress == 1
438+ }
439+ }
440+ }
441+
304442 InputFilterArea {
305443 anchors.fill: parent
306− blockInput: ApplicationManager.focusedApplicationId.length === 0 || launcher.shown
444+ blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
307445 || panel.indicators.shown
308446 }
309447
@@ -315,7 +453,7 @@ BasicShell {
315453 // We ignore any display-off signals when the proximity sensor
316454 // is active. This usually indicates something like a phone call.
317455 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
318− SessionManager.lock();
456+ greeter.showNow();
319457 }
320458
321459 // No reason to chew demo CPU when user isn't watching
@@ -327,12 +465,17 @@ BasicShell {
327465 }
328466 }
329467
330− function showHome(fromLauncher) {
331− var animate = fromLauncher && !stages.shown
468+ function showHome() {
469+ var animate = !greeter.shown && !stages.shown
470+ greeter.hide()
332471 dash.setCurrentScope("clickscope", animate, false)
333472 stages.hide()
334473 }
335474
475+ function hideIndicatorMenu(delay) {
476+ panel.hideIndicatorMenu(delay);
477+ }
478+
336479 Item {
337480 id: overlay
338481
@@ -349,8 +492,8 @@ BasicShell {
349492 }
350493 property string focusedAppId: ApplicationManager.focusedApplicationId
351494 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
352− fullscreenMode: focusedApplication && stages.fullscreen
353− searchVisible: dash.shown && dash.searchable
495+ fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown
496+ searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
354497
355498 InputFilterArea {
356499 anchors {
@@ -388,9 +531,8 @@ BasicShell {
388531 if (edgeDemo.running)
389532 return;
390533
391− showHome(true)
534+ showHome()
392535 }
393−
394536 onDash: {
395537 if (stages.shown && !stages.overlayMode) {
396538 if (!stages.locked) {
@@ -398,6 +540,10 @@ BasicShell {
398540 launcher.hide();
399541 }
400542 }
543+ if (greeter.shown) {
544+ greeter.hideRight();
545+ launcher.hide();
546+ }
401547 }
402548 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
403549 onLauncherApplicationSelected: {
@@ -414,7 +560,7 @@ BasicShell {
414560 Rectangle {
415561 id: modalNotificationBackground
416562
417− visible: notifications.useModal && (notifications.state == "narrow")
563+ visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
418564 color: "#000000"
419565 anchors.fill: parent
420566 opacity: 0.5
@@ -461,18 +607,11 @@ BasicShell {
461607 blockInput: height > 0
462608 }
463609 }
464−
465− Connections {
466− target: SessionManager
467− onActiveChanged: {
468− if (!SessionManager.active) {
469− launcher.hide()
470− panel.indicators.hide()
471− }
472− }
473− }
474610 }
475611
612+ focus: true
613+ onFocusChanged: if (!focus) forceActiveFocus();
614+
476615 InputFilterArea {
477616 anchors {
478617 top: parent.top
@@ -493,6 +632,12 @@ BasicShell {
493632 blockInput: true
494633 }
495634
635+ Binding {
636+ target: i18n
637+ property: "domain"
638+ value: "unity8"
639+ }
640+
496641 OSKController {
497642 anchors.topMargin: panel.panelHeight
498643 anchors.fill: parent // as needs to know the geometry of the shell
@@ -524,6 +669,7 @@ BasicShell {
524669
525670 EdgeDemo {
526671 id: edgeDemo
672+ greeter: greeter
527673 launcher: launcher
528674 dash: dash
529675 indicators: panel.indicators
@@ -532,6 +678,6 @@ BasicShell {
532678
533679 Connections {
534680 target: SessionBroadcast
535− onShowHome: showHome(false)
681+ onShowHome: showHome()
536682 }
537683}