@@ -21,19 +21,28 @@ 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"
3132import "Notifications"
3233import Unity.Notifications 1.0 as NotificationBackend
3334
34−BasicShell {
35+FocusScope {
3536 id: shell
3637
38+ // this is only here to select the width / height of the window if not running fullscreen
39+ property bool tablet: false
40+ width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
41+ height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
42+
43+ property real edgeSize: units.gu(2)
44+ property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
45+ property url background
3746 readonly property real panelHeight: panel.panelHeight
3847
3948 property bool dashShown: dash.shown
@@ -69,7 +78,17 @@ BasicShell {
6978 id: backgroundSettings
7079 schema.id: "org.gnome.desktop.background"
7180 }
72− backgroundSource: backgroundSettings.pictureUri
81+ property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
82+ onGSettingsPictureChanged: {
83+ shell.background = gSettingsPicture
84+ }
85+
86+ VolumeControl {
87+ id: volumeControl
88+ }
89+
90+ Keys.onVolumeUpPressed: volumeControl.volumeUp()
91+ Keys.onVolumeDownPressed: volumeControl.volumeDown()
7392
7493 Item {
7594 id: underlayClipper
@@ -116,9 +135,10 @@ BasicShell {
116135 id: dash
117136 objectName: "dash"
118137
138+ available: !greeter.shown && !lockscreen.shown
119139 hides: [stages, launcher, panel.indicators]
120− shown: disappearingAnimationProgress !== 1.0
121− enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
140+ shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
141+ enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
122142
123143 anchors {
124144 fill: parent
@@ -206,6 +226,7 @@ BasicShell {
206226 shown = true;
207227 panel.indicators.hide();
208228 edgeDemo.stopDemo();
229+ greeter.hide();
209230 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
210231 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
211232 }
@@ -246,12 +267,6 @@ BasicShell {
246267 }
247268 }
248269
249− Binding {
250− target: ApplicationManager
251− property: "suspended"
252− value: !SessionManager.active
253− }
254−
255270 Loader {
256271 id: applicationsDisplayLoader
257272 anchors.fill: parent
@@ -276,9 +291,132 @@ BasicShell {
276291 }
277292 }
278293
294+ Lockscreen {
295+ id: lockscreen
296+ objectName: "lockscreen"
297+
298+ readonly property int backgroundTopMargin: -panel.panelHeight
299+
300+ hides: [launcher, panel.indicators]
301+ shown: false
302+ enabled: true
303+ showAnimation: StandardAnimation { property: "opacity"; to: 1 }
304+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
305+ y: panel.panelHeight
306+ x: required ? 0 : - width
307+ width: parent.width
308+ height: parent.height - panel.panelHeight
309+ background: shell.background
310+ minPinLength: 4
311+ maxPinLength: 4
312+
313+ onEntered: LightDM.Greeter.respond(passphrase);
314+ onCancel: greeter.show()
315+
316+ Component.onCompleted: {
317+ if (LightDM.Users.count == 1) {
318+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
319+ }
320+ }
321+ }
322+
323+ Connections {
324+ target: LightDM.Greeter
325+
326+ onShowPrompt: {
327+ if (LightDM.Users.count == 1) {
328+ // TODO: There's no better way for now to determine if its a PIN or a passphrase.
329+ if (text == "PIN") {
330+ lockscreen.alphaNumeric = false
331+ } else {
332+ lockscreen.alphaNumeric = true
333+ }
334+ lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
335+ lockscreen.show();
336+ }
337+ }
338+
339+ onAuthenticationComplete: {
340+ if (LightDM.Greeter.promptless) {
341+ return;
342+ }
343+ if (LightDM.Greeter.authenticated) {
344+ lockscreen.hide();
345+ } else {
346+ lockscreen.clear(true);
347+ }
348+ }
349+ }
350+
351+ Rectangle {
352+ anchors.fill: parent
353+ color: "black"
354+ opacity: greeterWrapper.showProgress * 0.8
355+ }
356+
357+ Item {
358+ // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
359+ id: greeterWrapper
360+ x: launcher.progress
361+ y: panel.panelHeight
362+ width: parent.width
363+ height: parent.height - panel.panelHeight
364+
365+ Behavior on x {
366+ enabled: !launcher.dashSwipe
367+ StandardAnimation {}
368+ }
369+
370+ readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
371+
372+ Greeter {
373+ id: greeter
374+ objectName: "greeter"
375+
376+ available: true
377+ hides: [launcher, panel.indicators]
378+ shown: true
379+
380+ defaultBackground: shell.background
381+
382+ width: parent.width
383+ height: parent.height
384+
385+ dragHandleWidth: shell.edgeSize
386+
387+ onShownChanged: {
388+ if (shown) {
389+ lockscreen.reset();
390+ // If there is only one user, we start authenticating with that one here.
391+ // If there are more users, the Greeter will handle that
392+ if (LightDM.Users.count == 1) {
393+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
394+ }
395+ greeter.forceActiveFocus();
396+ }
397+ }
398+
399+ onUnlocked: greeter.hide()
400+ onSelected: {
401+ // Update launcher items for new user
402+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
403+ AccountsService.user = user;
404+ LauncherModel.setUser(user);
405+ }
406+
407+ onTease: launcher.tease()
408+
409+ Binding {
410+ target: ApplicationManager
411+ property: "suspended"
412+ value: greeter.shown && greeterWrapper.showProgress == 1
413+ }
414+ }
415+ }
416+
279417 InputFilterArea {
280418 anchors.fill: parent
281− blockInput: ApplicationManager.focusedApplicationId.length === 0 || launcher.shown
419+ blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
282420 || panel.indicators.shown
283421 }
284422
@@ -290,7 +428,7 @@ BasicShell {
290428 // We ignore any display-off signals when the proximity sensor
291429 // is active. This usually indicates something like a phone call.
292430 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
293− SessionManager.lock();
431+ greeter.showNow();
294432 }
295433
296434 // No reason to chew demo CPU when user isn't watching
@@ -302,12 +440,17 @@ BasicShell {
302440 }
303441 }
304442
305− function showHome(fromLauncher) {
306− var animate = fromLauncher && !stages.shown
443+ function showHome() {
444+ var animate = !greeter.shown && !stages.shown
445+ greeter.hide()
307446 dash.setCurrentScope("clickscope", animate, false)
308447 stages.hide()
309448 }
310449
450+ function hideIndicatorMenu(delay) {
451+ panel.hideIndicatorMenu(delay);
452+ }
453+
311454 Item {
312455 id: overlay
313456
@@ -324,8 +467,8 @@ BasicShell {
324467 }
325468 property string focusedAppId: ApplicationManager.focusedApplicationId
326469 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
327− fullscreenMode: focusedApplication && stages.fullscreen
328− searchVisible: dash.shown && dash.searchable
470+ fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown
471+ searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
329472
330473 InputFilterArea {
331474 anchors {
@@ -363,9 +506,8 @@ BasicShell {
363506 if (edgeDemo.running)
364507 return;
365508
366− showHome(true)
509+ showHome()
367510 }
368−
369511 onDash: {
370512 if (stages.shown && !stages.overlayMode) {
371513 if (!stages.locked) {
@@ -373,6 +515,10 @@ BasicShell {
373515 launcher.hide();
374516 }
375517 }
518+ if (greeter.shown) {
519+ greeter.hideRight();
520+ launcher.hide();
521+ }
376522 }
377523 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
378524 onLauncherApplicationSelected: {
@@ -389,7 +535,7 @@ BasicShell {
389535 Rectangle {
390536 id: modalNotificationBackground
391537
392− visible: notifications.useModal && (notifications.state == "narrow")
538+ visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
393539 color: "#000000"
394540 anchors.fill: parent
395541 opacity: 0.5
@@ -436,18 +582,11 @@ BasicShell {
436582 blockInput: height > 0
437583 }
438584 }
439−
440− Connections {
441− target: SessionManager
442− onActiveChanged: {
443− if (!SessionManager.active) {
444− launcher.hide()
445− panel.indicators.hide()
446− }
447− }
448− }
449585 }
450586
587+ focus: true
588+ onFocusChanged: if (!focus) forceActiveFocus();
589+
451590 InputFilterArea {
452591 anchors {
453592 top: parent.top
@@ -468,6 +607,12 @@ BasicShell {
468607 blockInput: true
469608 }
470609
610+ Binding {
611+ target: i18n
612+ property: "domain"
613+ value: "unity8"
614+ }
615+
471616 OSKController {
472617 anchors.topMargin: panel.panelHeight
473618 anchors.fill: parent // as needs to know the geometry of the shell
@@ -499,6 +644,7 @@ BasicShell {
499644
500645 EdgeDemo {
501646 id: edgeDemo
647+ greeter: greeter
502648 launcher: launcher
503649 dash: dash
504650 indicators: panel.indicators
@@ -507,6 +653,6 @@ BasicShell {
507653
508654 Connections {
509655 target: SessionBroadcast
510− onShowHome: showHome(false)
656+ onShowHome: showHome()
511657 }
512658}