@@ -19,8 +19,10 @@ 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
25+import Utils 0.1
2426import LightDM 0.1 as LightDM
2527import Powerd 0.1
2628import SessionBroadcast 0.1
@@ -34,7 +36,7 @@ import "Stages"
3436import Unity.Notifications 1.0 as NotificationBackend
3537import Unity.Session 0.1
3638
37−FocusScope {
39+Item {
3840 id: shell
3941
4042 // this is only here to select the width / height of the window if not running fullscreen
@@ -85,8 +87,31 @@ FocusScope {
8587 id: volumeControl
8688 }
8789
88− Keys.onVolumeUpPressed: volumeControl.volumeUp()
89− Keys.onVolumeDownPressed: volumeControl.volumeDown()
90+ WindowKeysFilter {
91+ // Handle but do not filter out volume keys
92+ Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
93+ Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
94+
95+ Keys.onPressed: {
96+ if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
97+ if (!powerKeyTimer.running) {
98+ powerKeyTimer.start();
99+ }
100+ event.accepted = true;
101+ } else {
102+ event.accepted = false;
103+ }
104+ }
105+
106+ Keys.onReleased: {
107+ if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
108+ powerKeyTimer.stop();
109+ event.accepted = true;
110+ } else {
111+ event.accepted = false;
112+ }
113+ }
114+ }
90115
91116 Item {
92117 id: underlay
@@ -95,9 +120,6 @@ FocusScope {
95120
96121 // Whether the underlay is fully covered by opaque UI elements.
97122 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
98−
99− // NB! Application surfaces are stacked behind the shell one. So they can only be seen by the user
100− // through the translucent parts of the shell surface.
101123 visible: !fullyCovered
102124
103125 Image {
@@ -169,14 +191,23 @@ FocusScope {
169191
170192 visible: !fullyHidden && !ApplicationManager.empty
171193
172− x: shown ? launcher.progress : stagesDragArea.progress
194+ x: {
195+ if (shown) {
196+ if (locked) {
197+ return 0;
198+ }
199+ return launcher.progress;
200+ } else {
201+ return stagesDragArea.progress
202+ }
203+ }
173204 Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
174205
175206 property bool shown: false
176207 onShownChanged: {
177208 if (shown) {
178− if (ApplicationManager.topmostApplication) {
179− ApplicationManager.focusApplication(ApplicationManager.topmostApplication.appId);
209+ if (ApplicationManager.count > 0) {
210+ ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
180211 }
181212 } else {
182213 if (ApplicationManager.focusedApplicationId) {
@@ -194,6 +225,8 @@ FocusScope {
194225 property bool fullyShown: x == 0
195226 property bool fullyHidden: x == width
196227
228+ property bool locked: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.locked : false
229+
197230 // It might technically not be fullyShown but visually it just looks so.
198231 property bool roughlyFullyShown: x >= 0 && x <= units.gu(1)
199232
@@ -230,7 +263,128 @@ FocusScope {
230263 }
231264 }
232265
266+ property bool dialogShown: false
267+
268+ Component {
269+ id: logoutDialog
270+ Dialog {
271+ id: dialogueLogout
272+ title: "Logout"
273+ text: "Are you sure that you want to logout?"
274+ Button {
275+ text: "Cancel"
276+ onClicked: {
277+ PopupUtils.close(dialogueLogout);
278+ stages.dialogShown = false;
279+ }
280+ }
281+ Button {
282+ text: "Yes"
283+ onClicked: {
284+ DBusUnitySessionService.Logout();
285+ PopupUtils.close(dialogueLogout);
286+ stages.dialogShown = false;
287+ }
288+ }
289+ }
290+ }
291+
292+ Component {
293+ id: shutdownDialog
294+ Dialog {
295+ id: dialogueShutdown
296+ title: "Shutdown"
297+ text: "Are you sure that you want to shutdown?"
298+ Button {
299+ text: "Cancel"
300+ onClicked: {
301+ PopupUtils.close(dialogueShutdown);
302+ stages.dialogShown = false;
303+ }
304+ }
305+ Button {
306+ text: "Yes"
307+ onClicked: {
308+ dBusUnitySessionServiceConnection.closeAllApps();
309+ DBusUnitySessionService.Shutdown();
310+ PopupUtils.close(dialogueShutdown);
311+ stages.dialogShown = false;
312+ }
313+ }
314+ }
315+ }
316+
317+ Component {
318+ id: rebootDialog
319+ Dialog {
320+ id: dialogueReboot
321+ title: "Reboot"
322+ text: "Are you sure that you want to reboot?"
323+ Button {
324+ text: "Cancel"
325+ onClicked: {
326+ PopupUtils.close(dialogueReboot)
327+ stages.dialogShown = false;
328+ }
329+ }
330+ Button {
331+ text: "Yes"
332+ onClicked: {
333+ dBusUnitySessionServiceConnection.closeAllApps();
334+ DBusUnitySessionService.Reboot();
335+ PopupUtils.close(dialogueReboot);
336+ stages.dialogShown = false;
337+ }
338+ }
339+ }
340+ }
341+
342+ Component {
343+ id: powerDialog
344+ Dialog {
345+ id: dialoguePower
346+ title: "Power"
347+ text: i18n.tr("Are you sure you would like to turn power off?")
348+ Button {
349+ text: i18n.tr("Power off")
350+ onClicked: {
351+ dBusUnitySessionServiceConnection.closeAllApps();
352+ PopupUtils.close(dialoguePower);
353+ stages.dialogShown = false;
354+ shutdownFadeOutRectangle.enabled = true;
355+ shutdownFadeOutRectangle.visible = true;
356+ shutdownFadeOut.start();
357+ }
358+ }
359+ Button {
360+ text: i18n.tr("Restart")
361+ onClicked: {
362+ dBusUnitySessionServiceConnection.closeAllApps();
363+ DBusUnitySessionService.Reboot();
364+ PopupUtils.close(dialoguePower);
365+ stages.dialogShown = false;
366+ }
367+ }
368+ Button {
369+ text: i18n.tr("Cancel")
370+ onClicked: {
371+ PopupUtils.close(dialoguePower);
372+ stages.dialogShown = false;
373+ }
374+ }
375+ }
376+ }
377+
378+ function showPowerDialog() {
379+ if (!stages.dialogShown) {
380+ stages.dialogShown = true;
381+ PopupUtils.open(powerDialog);
382+ }
383+ }
384+
233385 Connections {
386+ id: dBusUnitySessionServiceConnection
387+ objectName: "dBusUnitySessionServiceConnection"
234388 target: DBusUnitySessionService
235389
236390 function closeAllApps() {
@@ -244,8 +398,27 @@ FocusScope {
244398 }
245399
246400 onLogoutRequested: {
247− // TODO: Display a dialog to ask the user to confirm.
248− DBusUnitySessionService.Logout();
401+ // Display a dialog to ask the user to confirm.
402+ if (!stages.dialogShown) {
403+ stages.dialogShown = true;
404+ PopupUtils.open(logoutDialog);
405+ }
406+ }
407+
408+ onShutdownRequested: {
409+ // Display a dialog to ask the user to confirm.
410+ if (!stages.dialogShown) {
411+ stages.dialogShown = true;
412+ PopupUtils.open(shutdownDialog);
413+ }
414+ }
415+
416+ onRebootRequested: {
417+ // Display a dialog to ask the user to confirm.
418+ if (!stages.dialogShown) {
419+ stages.dialogShown = true;
420+ PopupUtils.open(rebootDialog);
421+ }
249422 }
250423
251424 onLogoutReady: {
@@ -274,14 +447,14 @@ FocusScope {
274447 Binding {
275448 target: applicationsDisplayLoader.item
276449 property: "interactive"
277− value: stages.roughlyFullyShown
450+ value: stages.roughlyFullyShown && !greeter.shown && !lockscreen.shown
278451 }
279452 }
280453 }
281454
282455 InputMethod {
283456 id: inputMethod
284− anchors.fill: parent
457+ anchors { fill: parent; topMargin: panel.panelHeight }
285458 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
286459 }
287460
@@ -337,6 +510,8 @@ FocusScope {
337510 Connections {
338511 target: LightDM.Greeter
339512
513+ onShowGreeter: greeter.show()
514+
340515 onShowPrompt: {
341516 if (LightDM.Users.count == 1) {
342517 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
@@ -362,6 +537,12 @@ FocusScope {
362537 }
363538 }
364539
540+ Binding {
541+ target: LightDM.Greeter
542+ property: "active"
543+ value: greeter.shown || lockscreen.shown
544+ }
545+
365546 Rectangle {
366547 anchors.fill: parent
367548 color: "black"
@@ -401,6 +582,9 @@ FocusScope {
401582 onShownChanged: {
402583 if (shown) {
403584 lockscreen.reset();
585+ if (!LightDM.Greeter.promptless) {
586+ lockscreen.show();
587+ }
404588 // If there is only one user, we start authenticating with that one here.
405589 // If there are more users, the Greeter will handle that
406590 if (LightDM.Users.count == 1) {
@@ -477,8 +661,8 @@ FocusScope {
477661 }
478662
479663 property bool topmostApplicationIsFullscreen:
480− ApplicationManager.topmostApplication &&
481− ApplicationManager.topmostApplication.fullscreen
664+ ApplicationManager.focusedApplicationId &&
665+ ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
482666
483667 fullscreenMode: stages.roughlyFullyShown && topmostApplicationIsFullscreen
484668 && !greeter.shown && !lockscreen.shown
@@ -565,9 +749,6 @@ FocusScope {
565749 }
566750 }
567751
568− focus: true
569− onFocusChanged: if (!focus) forceActiveFocus();
570−
571752 Binding {
572753 target: i18n
573754 property: "domain"
@@ -604,4 +785,34 @@ FocusScope {
604785 target: SessionBroadcast
605786 onShowHome: showHome()
606787 }
788+
789+ Timer {
790+ id: powerKeyTimer
791+ interval: 2000
792+ repeat: false
793+ triggeredOnStart: false
794+
795+ onTriggered: {
796+ stages.showPowerDialog();
797+ }
798+ }
799+
800+ Rectangle {
801+ id: shutdownFadeOutRectangle
802+ enabled: false
803+ visible: false
804+ color: "black"
805+ anchors.fill: parent
806+ opacity: 0.0
807+ NumberAnimation on opacity {
808+ id: shutdownFadeOut
809+ from: 0.0
810+ to: 1.0
811+ onStopped: {
812+ if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
813+ DBusUnitySessionService.Shutdown();
814+ }
815+ }
816+ }
817+ }
607818}