@@ -19,6 +19,7 @@ import AccountsService 0.1
1919import GSettings 1.0
2020import Unity.Application 0.1
2121import Ubuntu.Components 0.1
22+import Ubuntu.Components.Popups 0.1
2223import Ubuntu.Gestures 0.1
2324import Unity.Launcher 0.1
2425import LightDM 0.1 as LightDM
@@ -136,7 +137,7 @@ FocusScope {
136137 id: dash
137138 objectName: "dash"
138139
139− available: !greeter.shown && !lockscreen.shown
140+ available: !LightDM.Greeter.active
140141 hides: [stages, launcher, panel.indicators]
141142 shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
142143 enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
@@ -199,7 +200,7 @@ FocusScope {
199200
200201 x: {
201202 if (shown) {
202− if (overlayMode || locked) {
203+ if (overlayMode || locked || greeter.fakeActiveForApp !== "") {
203204 return 0;
204205 }
205206 return launcher.progress
@@ -244,10 +245,17 @@ FocusScope {
244245 target: ApplicationManager
245246
246247 onFocusRequested: {
248+ if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
249+ lockscreen.show();
250+ }
251+ greeter.hide();
247252 stages.show(true);
248253 }
249254
250255 onFocusedApplicationIdChanged: {
256+ if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
257+ lockscreen.show();
258+ }
251259 if (ApplicationManager.focusedApplicationId.length > 0) {
252260 stages.show(false);
253261 } else {
@@ -268,7 +276,128 @@ FocusScope {
268276 }
269277 }
270278
279+ property bool dialogShown: false
280+
281+ Component {
282+ id: logoutDialog
283+ Dialog {
284+ id: dialogueLogout
285+ title: "Logout"
286+ text: "Are you sure that you want to logout?"
287+ Button {
288+ text: "Cancel"
289+ onClicked: {
290+ PopupUtils.close(dialogueLogout);
291+ stages.dialogShown = false;
292+ }
293+ }
294+ Button {
295+ text: "Yes"
296+ onClicked: {
297+ DBusUnitySessionService.Logout();
298+ PopupUtils.close(dialogueLogout);
299+ stages.dialogShown = false;
300+ }
301+ }
302+ }
303+ }
304+
305+ Component {
306+ id: shutdownDialog
307+ Dialog {
308+ id: dialogueShutdown
309+ title: "Shutdown"
310+ text: "Are you sure that you want to shutdown?"
311+ Button {
312+ text: "Cancel"
313+ onClicked: {
314+ PopupUtils.close(dialogueShutdown);
315+ stages.dialogShown = false;
316+ }
317+ }
318+ Button {
319+ text: "Yes"
320+ onClicked: {
321+ dBusUnitySessionServiceConnection.closeAllApps();
322+ DBusUnitySessionService.Shutdown();
323+ PopupUtils.close(dialogueShutdown);
324+ stages.dialogShown = false;
325+ }
326+ }
327+ }
328+ }
329+
330+ Component {
331+ id: rebootDialog
332+ Dialog {
333+ id: dialogueReboot
334+ title: "Reboot"
335+ text: "Are you sure that you want to reboot?"
336+ Button {
337+ text: "Cancel"
338+ onClicked: {
339+ PopupUtils.close(dialogueReboot)
340+ stages.dialogShown = false;
341+ }
342+ }
343+ Button {
344+ text: "Yes"
345+ onClicked: {
346+ dBusUnitySessionServiceConnection.closeAllApps();
347+ DBusUnitySessionService.Reboot();
348+ PopupUtils.close(dialogueReboot);
349+ stages.dialogShown = false;
350+ }
351+ }
352+ }
353+ }
354+
355+ Component {
356+ id: powerDialog
357+ Dialog {
358+ id: dialoguePower
359+ title: "Power"
360+ text: i18n.tr("Are you sure you would like to turn power off?")
361+ Button {
362+ text: i18n.tr("Power off")
363+ onClicked: {
364+ dBusUnitySessionServiceConnection.closeAllApps();
365+ PopupUtils.close(dialoguePower);
366+ stages.dialogShown = false;
367+ shutdownFadeOutRectangle.enabled = true;
368+ shutdownFadeOutRectangle.visible = true;
369+ shutdownFadeOut.start();
370+ }
371+ }
372+ Button {
373+ text: i18n.tr("Restart")
374+ onClicked: {
375+ dBusUnitySessionServiceConnection.closeAllApps();
376+ DBusUnitySessionService.Reboot();
377+ PopupUtils.close(dialoguePower);
378+ stages.dialogShown = false;
379+ }
380+ }
381+ Button {
382+ text: i18n.tr("Cancel")
383+ onClicked: {
384+ PopupUtils.close(dialoguePower);
385+ stages.dialogShown = false;
386+ }
387+ }
388+ }
389+ }
390+
391+ function showPowerDialog() {
392+ if (!stages.dialogShown) {
393+ stages.dialogShown = true;
394+ PopupUtils.open(powerDialog);
395+ }
396+ }
397+
271398 Connections {
399+ id: dBusUnitySessionServiceConnection
400+ objectName: "dBusUnitySessionServiceConnection"
272401 target: DBusUnitySessionService
273402
274403 function closeAllApps() {
@@ -282,8 +411,27 @@ FocusScope {
282411 }
283412
284413 onLogoutRequested: {
285− // TODO: Display a dialog to ask the user to confirm.
286− DBusUnitySessionService.Logout();
414+ // Display a dialog to ask the user to confirm.
415+ if (!stages.dialogShown) {
416+ stages.dialogShown = true;
417+ PopupUtils.open(logoutDialog);
418+ }
419+ }
420+
421+ onShutdownRequested: {
422+ // Display a dialog to ask the user to confirm.
423+ if (!stages.dialogShown) {
424+ stages.dialogShown = true;
425+ PopupUtils.open(shutdownDialog);
426+ }
427+ }
428+
429+ onRebootRequested: {
430+ // Display a dialog to ask the user to confirm.
431+ if (!stages.dialogShown) {
432+ stages.dialogShown = true;
433+ PopupUtils.open(rebootDialog);
434+ }
287435 }
288436
289437 onLogoutReady: {
@@ -298,6 +446,11 @@ FocusScope {
298446
299447 source: shell.sideStageEnabled ? "Stages/StageWithSideStage.qml" : "Stages/PhoneStage.qml"
300448
449+ Binding {
450+ target: applicationsDisplayLoader.item
451+ property: "objectName"
452+ value: "stage"
453+ }
301454 Binding {
302455 target: applicationsDisplayLoader.item
303456 property: "moving"
@@ -313,6 +466,11 @@ FocusScope {
313466 property: "dragAreaWidth"
314467 value: shell.edgeSize
315468 }
469+ Binding {
470+ target: applicationsDisplayLoader.item
471+ property: "spreadEnabled"
472+ value: greeter.fakeActiveForApp === "" // to support emergency dialer hack
473+ }
316474 }
317475 }
318476
@@ -337,6 +495,13 @@ FocusScope {
337495
338496 onEntered: LightDM.Greeter.respond(passphrase);
339497 onCancel: greeter.show()
498+ onEmergencyCall: {
499+ greeter.fakeActiveForApp = "dialer-app"
500+ shell.activateApplication("dialer-app")
501+ lockscreen.hide()
502+ }
503+
504+ onShownChanged: if (shown) greeter.fakeActiveForApp = ""
340505
341506 Component.onCompleted: {
342507 if (LightDM.Users.count == 1) {
@@ -348,6 +513,8 @@ FocusScope {
348513 Connections {
349514 target: LightDM.Greeter
350515
516+ onShowGreeter: greeter.show()
517+
351518 onShowPrompt: {
352519 if (LightDM.Users.count == 1) {
353520 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
@@ -367,12 +534,19 @@ FocusScope {
367534 }
368535 if (LightDM.Greeter.authenticated) {
369536 lockscreen.hide();
537+ greeter.login();
370538 } else {
371539 lockscreen.clear(true);
372540 }
373541 }
374542 }
375543
544+ Binding {
545+ target: LightDM.Greeter
546+ property: "active"
547+ value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
548+ }
549+
376550 Rectangle {
377551 anchors.fill: parent
378552 color: "black"
@@ -393,11 +567,16 @@ FocusScope {
393567 }
394568
395569 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
570+ onShowProgressChanged: if (LightDM.Greeter.promptless && showProgress === 0) greeter.login()
396571
397572 Greeter {
398573 id: greeter
399574 objectName: "greeter"
400575
576+ signal sessionStarted() // helpful for tests
577+
578+ property string fakeActiveForApp: ""
579+
401580 available: true
402581 hides: [launcher, panel.indicators]
403582 shown: true
@@ -409,14 +588,28 @@ FocusScope {
409588
410589 dragHandleWidth: shell.edgeSize
411590
591+ function login() {
592+ enabled = false;
593+ LightDM.Greeter.startSessionSync();
594+ sessionStarted();
595+ greeter.hide();
596+ lockscreen.hide();
597+ launcher.hide();
598+ enabled = true;
599+ }
600+
412601 onShownChanged: {
413602 if (shown) {
414603 lockscreen.reset();
604+ if (!LightDM.Greeter.promptless) {
605+ lockscreen.show();
606+ }
415607 // If there is only one user, we start authenticating with that one here.
416608 // If there are more users, the Greeter will handle that
417609 if (LightDM.Users.count == 1) {
418610 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
419611 }
612+ greeter.fakeActiveForApp = "";
420613 greeter.forceActiveFocus();
421614 }
422615 }
@@ -466,14 +659,38 @@ FocusScope {
466659 }
467660
468661 function showHome() {
469− var animate = !greeter.shown && !stages.shown
470− greeter.hide()
662+ if (edgeDemo.running) {
663+ return
664+ }
665+
666+ if (LightDM.Greeter.active) {
667+ if (!LightDM.Greeter.promptless) {
668+ lockscreen.show()
669+ }
670+ greeter.hide()
671+ }
672+
673+ var animate = !LightDM.Greeter.active && !stages.shown
471674 dash.setCurrentScope("clickscope", animate, false)
472675 stages.hide()
473676 }
474677
475− function hideIndicatorMenu(delay) {
476− panel.hideIndicatorMenu(delay);
678+ function showDash() {
679+ if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
680+ return;
681+ }
682+
683+ if (stages.shown && !stages.overlayMode && !stages.locked) {
684+ stages.hide();
685+ launcher.fadeOut();
686+ } else {
687+ launcher.switchToNextState("visible");
688+ }
689+
690+ if (greeter.shown) {
691+ greeter.hideRight();
692+ launcher.fadeOut();
693+ }
477694 }
478695
479696 Item {
@@ -483,17 +700,18 @@ FocusScope {
483700
484701 Panel {
485702 id: panel
703+ objectName: "panel"
486704 anchors.fill: parent //because this draws indicator menus
487705 indicators {
488706 hides: [launcher]
489− available: edgeDemo.panelEnabled
707+ available: edgeDemo.panelEnabled && greeter.fakeActiveForApp === ""
490708 contentEnabled: edgeDemo.panelContentEnabled
491709 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
492710 panelHeight: units.gu(3)
493711 }
494712 property string focusedAppId: ApplicationManager.focusedApplicationId
495713 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
496− fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown
714+ fullscreenMode: (focusedApplication && stages.fullscreen && !LightDM.Greeter.active) || greeter.fakeActiveForApp !== ""
497715
498716 InputFilterArea {
499717 anchors {
@@ -518,6 +736,7 @@ FocusScope {
518736
519737 Launcher {
520738 id: launcher
739+ objectName: "launcher"
521740
522741 readonly property bool dashSwipe: progress > 0
523742
@@ -525,29 +744,15 @@ FocusScope {
525744 anchors.bottom: parent.bottom
526745 width: parent.width
527746 dragAreaWidth: shell.edgeSize
528− available: edgeDemo.launcherEnabled
529−
530− onShowDashHome: {
531− if (edgeDemo.running)
532− return;
533−
534− showHome()
535− }
536− onDash: {
537− if (stages.shown && !stages.overlayMode && !stages.locked) {
538− stages.hide();
539− launcher.fadeOut();
540− } else {
541− launcher.switchToNextState("visible");
542− }
747+ available: edgeDemo.launcherEnabled && greeter.fakeActiveForApp === ""
543748
544− if (greeter.shown) {
545− greeter.hideRight();
546− launcher.fadeOut();
547− }
548− }
749+ onShowDashHome: showHome()
750+ onDash: showDash()
549751 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
550752 onLauncherApplicationSelected: {
753+ if (greeter.fakeActiveForApp !== "") {
754+ lockscreen.show()
755+ }
551756 if (!edgeDemo.running)
552757 shell.activateApplication(appId)
553758 }
@@ -679,4 +884,50 @@ FocusScope {
679884 target: SessionBroadcast
680885 onShowHome: showHome()
681886 }
887+
888+ Keys.onPressed: {
889+ if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
890+ if (!powerKeyTimer.running) {
891+ powerKeyTimer.start();
892+ }
893+ event.accepted = true;
894+ }
895+ }
896+
897+ Keys.onReleased: {
898+ if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
899+ powerKeyTimer.stop();
900+ event.accepted = true;
901+ }
902+ }
903+
904+ Timer {
905+ id: powerKeyTimer
906+ interval: 2000
907+ repeat: false
908+ triggeredOnStart: false
909+
910+ onTriggered: {
911+ stages.showPowerDialog();
912+ }
913+ }
914+
915+ Rectangle {
916+ id: shutdownFadeOutRectangle
917+ enabled: false
918+ visible: false
919+ color: "black"
920+ anchors.fill: parent
921+ opacity: 0.0
922+ NumberAnimation on opacity {
923+ id: shutdownFadeOut
924+ from: 0.0
925+ to: 1.0
926+ onStopped: {
927+ if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
928+ DBusUnitySessionService.Shutdown();
929+ }
930+ }
931+ }
932+ }
682933}