on abd3899 help sign in
unity8/qml/Shell.qml
845 lines 29 kB history raw
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
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.
7 *
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.
12 *
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/>.
15 */
17import QtQuick 2.0
18import QtQuick.Window 2.0
19import AccountsService 0.1
20import GSettings 1.0
21import Unity.Application 0.1
22import Ubuntu.Components 0.1
23import Ubuntu.Components.Popups 1.0
24import Ubuntu.Gestures 0.1
25import Ubuntu.SystemImage 0.1
26import Ubuntu.Telephony 0.1 as Telephony
27import Unity.Connectivity 0.1
28import Unity.Launcher 0.1
29import Utils 0.1
30import LightDM 0.1 as LightDM
31import Powerd 0.1
32import SessionBroadcast 0.1
33import "Greeter"
34import "Launcher"
35import "Panel"
36import "Components"
37import "Notifications"
38import "Stages"
39import "Panel/Indicators"
40import "Wizard"
41import Unity.Notifications 1.0 as NotificationBackend
42import Unity.Session 0.1
43import Unity.DashCommunicator 0.1
45Item {
46 id: shell
48 // Disable everything so that user can't swipe greeter or launcher until
49 // we get first prompt/authenticate, which will re-enable the shell.
50 enabled: false
52 // this is only here to select the width / height of the window if not running fullscreen
53 property bool tablet: false
54 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
55 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
57 property real edgeSize: units.gu(2)
58 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
59 property url background: asImageTester.status == Image.Ready ? asImageTester.source
60 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
61 readonly property real panelHeight: panel.panelHeight
63 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock
64 readonly property alias hasLockedApp: greeter.hasLockedApp
65 readonly property bool forcedUnlock: edgeDemo.running
66 onForcedUnlockChanged: if (forcedUnlock) lockscreen.hide()
68 property bool sideStageEnabled: shell.width >= units.gu(100)
69 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
71 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
72 property int failedLoginsDelayAttempts: 7 // number of failed logins
73 property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
75 property int orientation
76 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
77 onDeviceOrientationAngleChanged: {
78 if (!OrientationLock.enabled) {
79 orientation = Screen.orientation;
80 }
81 }
82 readonly property bool orientationLockEnabled: OrientationLock.enabled
83 onOrientationLockEnabledChanged: {
84 if (orientationLockEnabled) {
85 OrientationLock.savedOrientation = Screen.orientation;
86 } else {
87 orientation = Screen.orientation;
88 }
89 }
91 function activateApplication(appId) {
92 if (ApplicationManager.findApplication(appId)) {
93 ApplicationManager.requestFocusApplication(appId);
94 } else {
95 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
96 ApplicationManager.startApplication(appId, execFlags);
97 }
98 }
100 function startLockedApp(app) {
101 if (shell.locked) {
102 greeter.lockedApp = app;
103 }
104 shell.activateApplication(app);
105 }
107 // This is a dummy image to detect if the custom AS set wallpaper loads successfully.
108 Image {
109 id: asImageTester
110 source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : ""
111 height: 0
112 width: 0
113 sourceSize.height: 0
114 sourceSize.width: 0
115 }
117 GSettings {
118 id: backgroundSettings
119 schema.id: "org.gnome.desktop.background"
120 }
122 // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully.
123 Image {
124 id: gsImageTester
125 source: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : ""
126 height: 0
127 width: 0
128 sourceSize.height: 0
129 sourceSize.width: 0
130 }
132 Binding {
133 target: LauncherModel
134 property: "applicationManager"
135 value: ApplicationManager
136 }
138 Component.onCompleted: {
139 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
140 if (ApplicationManager.count > 0) {
141 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
142 }
143 if (orientationLockEnabled) {
144 orientation = OrientationLock.savedOrientation;
145 }
146 }
148 VolumeControl {
149 id: volumeControl
150 }
152 DashCommunicator {
153 id: dash
154 objectName: "dashCommunicator"
155 }
157 PhysicalKeysFilter {
158 id: physicalKeysFilter
160 onPowerPressed: dialogs.onPowerKeyPressed();
161 onVolumeDownPressed: volumeControl.volumeDown()
162 onVolumeUpPressed: volumeControl.volumeUp()
163 onScreenshotPressed: screenGrabber.capture()
164 }
166 ScreenGrabber {
167 id: screenGrabber
168 z: edgeDemo.z + 10
169 enabled: Powerd.status === Powerd.On
170 }
172 Binding {
173 target: ApplicationManager
174 property: "forceDashActive"
175 value: launcher.shown || launcher.dashSwipe
176 }
178 WindowKeysFilter {
179 Keys.onPressed: {
180 event.accepted = physicalKeysFilter.onKeyPressed(event.key);
181 }
183 Keys.onReleased: {
184 event.accepted = physicalKeysFilter.onKeyReleased(event.key);
185 }
186 }
188 Item {
189 id: stages
190 objectName: "stages"
191 width: parent.width
192 height: parent.height
193 visible: !ApplicationManager.empty
195 Connections {
196 target: ApplicationManager
197 onFocusRequested: {
198 if (greeter.narrowMode) {
199 if (appId === "dialer-app" && callManager.hasCalls && shell.locked) {
200 // If we are in the middle of a call, make dialer lockedApp and show it.
201 // This can happen if user backs out of dialer back to greeter, then
202 // launches dialer again.
203 greeter.lockedApp = appId;
204 }
205 if (greeter.hasLockedApp) {
206 if (appId === greeter.lockedApp) {
207 lockscreen.hide() // show locked app
208 } else {
209 greeter.startUnlock() // show lockscreen if necessary
210 }
211 }
212 greeter.hide();
213 } else {
214 if (LightDM.Greeter.active) {
215 greeter.startUnlock()
216 }
217 }
218 }
220 onFocusedApplicationIdChanged: {
221 if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
222 greeter.startUnlock()
223 }
224 panel.indicators.hide();
225 }
227 onApplicationAdded: {
228 if (greeter.shown && appId != "unity8-dash") {
229 greeter.startUnlock()
231 // If this happens on first boot, we may be in edge
232 // tutorial or wizard while receiving a call. But a call
233 // is more important than wizard so just bail out of those.
234 if (edgeDemo.running) {
235 edgeDemo.hideEdgeDemos();
236 wizard.hide();
237 }
238 }
239 if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
240 lockscreen.hide() // show locked app
241 }
242 launcher.hide();
243 }
244 }
246 Loader {
247 id: applicationsDisplayLoader
248 objectName: "applicationsDisplayLoader"
249 anchors.fill: parent
251 // When we have a locked app, we only want to show that one app.
252 // FIXME: do this in a less traumatic way. We currently only allow
253 // locked apps in phone mode (see FIXME in Lockscreen component in
254 // this same file). When that changes, we need to do something
255 // nicer here. But this code is currently just to prevent a
256 // theoretical attack where user enters lockedApp mode, then makes
257 // the screen larger (maybe connects to monitor) and tries to enter
258 // tablet mode.
259 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
260 source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
262 Binding {
263 target: applicationsDisplayLoader.item
264 property: "objectName"
265 value: "stage"
266 }
267 Binding {
268 target: applicationsDisplayLoader.item
269 property: "dragAreaWidth"
270 value: shell.edgeSize
271 }
272 Binding {
273 target: applicationsDisplayLoader.item
274 property: "maximizedAppTopMargin"
275 // Not just using panel.panelHeight as that changes depending on the focused app.
276 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
277 }
278 Binding {
279 target: applicationsDisplayLoader.item
280 property: "interactive"
281 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0 && !notifications.useModal
282 }
283 Binding {
284 target: applicationsDisplayLoader.item
285 property: "spreadEnabled"
286 value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
287 }
288 Binding {
289 target: applicationsDisplayLoader.item
290 property: "inverseProgress"
291 value: launcher.progress
292 }
293 Binding {
294 target: applicationsDisplayLoader.item
295 property: "orientation"
296 value: shell.orientation
297 }
298 }
299 }
301 InputMethod {
302 id: inputMethod
303 objectName: "inputMethod"
304 anchors { fill: parent; topMargin: panel.panelHeight }
305 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
306 }
308 Connections {
309 target: SurfaceManager
310 onSurfaceCreated: {
311 if (surface.type == MirSurfaceItem.InputMethod) {
312 inputMethod.surface = surface;
313 }
314 }
316 onSurfaceDestroyed: {
317 if (inputMethod.surface == surface) {
318 inputMethod.surface = null;
319 surface.parent = null;
320 }
321 if (!surface.parent) {
322 // there's no one displaying it. delete it right away
323 surface.release();
324 }
325 }
326 }
327 Connections {
328 target: SessionManager
329 onSessionStopping: {
330 if (!session.parentSession && !session.application) {
331 // nothing is using it. delete it right away
332 session.release();
333 }
334 }
335 }
337 Lockscreen {
338 id: lockscreen
339 objectName: "lockscreen"
341 hides: [launcher, panel.indicators]
342 shown: false
343 enabled: true
344 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
345 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
346 y: panel.panelHeight
347 visible: required
348 width: parent.width
349 height: parent.height - panel.panelHeight
350 background: shell.background
351 darkenBackground: 0.4
352 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
353 minPinLength: 4
354 maxPinLength: 4
356 property string promptText
357 infoText: promptText !== "" ? i18n.tr("Enter %1").arg(promptText) :
358 alphaNumeric ? i18n.tr("Enter passphrase") :
359 i18n.tr("Enter passcode")
360 errorText: promptText !== "" ? i18n.tr("Sorry, incorrect %1").arg(promptText) :
361 alphaNumeric ? i18n.tr("Sorry, incorrect passphrase") + "\n" +
362 i18n.tr("Please re-enter") :
363 i18n.tr("Sorry, incorrect passcode")
365 // FIXME: We *should* show emergency dialer if there is a SIM present,
366 // regardless of whether the side stage is enabled. But right now,
367 // the assumption is that narrow screens are phones which have SIMs
368 // and wider screens are tablets which don't. When we do allow this
369 // on devices with a side stage and a SIM, work should be done to
370 // ensure that the main stage is disabled while the dialer is present
371 // in the side stage. See the FIXME in the stage loader in this file.
372 showEmergencyCallButton: !shell.sideStageEnabled
374 onEntered: LightDM.Greeter.respond(passphrase);
375 onCancel: greeter.show()
376 onEmergencyCall: startLockedApp("dialer-app")
378 onShownChanged: if (shown) greeter.lockedApp = ""
380 function maybeShow() {
381 if (!shell.forcedUnlock) {
382 show()
383 }
384 }
386 Timer {
387 id: forcedDelayTimer
388 interval: 1000 * 60
389 onTriggered: {
390 if (lockscreen.delayMinutes > 0) {
391 lockscreen.delayMinutes -= 1
392 if (lockscreen.delayMinutes > 0) {
393 start() // go again
394 }
395 }
396 }
397 }
399 Component.onCompleted: {
400 if (greeter.narrowMode) {
401 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
402 }
403 }
404 }
406 Connections {
407 target: LightDM.Greeter
409 onShowGreeter: greeter.show()
410 onHideGreeter: greeter.login()
412 onShowPrompt: {
413 shell.enabled = true;
414 if (!LightDM.Greeter.active) {
415 return; // could happen if hideGreeter() comes in before we prompt
416 }
417 if (greeter.narrowMode) {
418 lockscreen.promptText = isDefaultPrompt ? "" : text.toLowerCase();
419 lockscreen.maybeShow();
420 }
421 }
423 onPromptlessChanged: {
424 if (!LightDM.Greeter.active) {
425 return; // could happen if hideGreeter() comes in before we prompt
426 }
427 if (greeter.narrowMode) {
428 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
429 lockscreen.hide()
430 } else {
431 lockscreen.reset();
432 lockscreen.maybeShow();
433 }
434 }
435 }
437 onAuthenticationComplete: {
438 shell.enabled = true;
439 if (LightDM.Greeter.authenticated) {
440 AccountsService.failedLogins = 0
441 }
442 // Else only penalize user for a failed login if they actually were
443 // prompted for a password. We do this below after the promptless
444 // early exit.
446 if (LightDM.Greeter.promptless) {
447 return;
448 }
450 if (LightDM.Greeter.authenticated) {
451 greeter.login();
452 } else {
453 AccountsService.failedLogins++
454 if (maxFailedLogins >= 2) { // require at least a warning
455 if (AccountsService.failedLogins === maxFailedLogins - 1) {
456 var title = lockscreen.alphaNumeric ?
457 i18n.tr("Sorry, incorrect passphrase.") :
458 i18n.tr("Sorry, incorrect passcode.")
459 var text = i18n.tr("This will be your last attempt.") + " " +
460 (lockscreen.alphaNumeric ?
461 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
462 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
463 lockscreen.showInfoPopup(title, text)
464 } else if (AccountsService.failedLogins >= maxFailedLogins) {
465 SystemImage.factoryReset() // Ouch!
466 }
467 }
468 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
469 lockscreen.delayMinutes = failedLoginsDelayMinutes
470 forcedDelayTimer.start()
471 }
473 lockscreen.clear(true);
474 if (greeter.narrowMode) {
475 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
476 }
477 }
478 }
479 }
481 Binding {
482 target: LightDM.Greeter
483 property: "active"
484 value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
485 }
487 Rectangle {
488 anchors.fill: parent
489 color: "black"
490 opacity: greeterWrapper.showProgress * 0.8
491 }
493 Item {
494 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
495 id: greeterWrapper
496 objectName: "greeterWrapper"
497 x: (greeter.narrowMode && greeter.showProgress > 0) ? launcher.progress : 0
498 y: panel.panelHeight
499 width: parent.width
500 height: parent.height - panel.panelHeight
502 Behavior on x {
503 enabled: !launcher.dashSwipe
504 StandardAnimation {}
505 }
507 property bool fullyShown: showProgress === 1.0
508 onFullyShownChanged: {
509 // Wait until the greeter is completely covering lockscreen before resetting it.
510 if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
511 lockscreen.reset();
512 lockscreen.maybeShow();
513 }
514 }
516 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
517 onShowProgressChanged: {
518 if (showProgress === 0) {
519 if ((LightDM.Greeter.promptless && LightDM.Greeter.authenticated) || shell.forcedUnlock) {
520 greeter.login()
521 } else if (greeter.narrowMode) {
522 lockscreen.clear(false) // to reset focus if necessary
523 }
524 }
525 }
527 Greeter {
528 id: greeter
529 objectName: "greeter"
531 signal sessionStarted() // helpful for tests
533 property string lockedApp: ""
534 property bool hasLockedApp: lockedApp !== ""
536 available: true
537 hides: [launcher, panel.indicators]
538 shown: true
539 loadContent: required || lockscreen.required // keeps content in memory for quick show()
541 locked: shell.locked
543 background: shell.background
545 width: parent.width
546 height: parent.height
548 dragHandleWidth: shell.edgeSize
550 function startUnlock() {
551 if (narrowMode) {
552 if (!LightDM.Greeter.authenticated) {
553 lockscreen.maybeShow()
554 }
555 hide()
556 } else {
557 show()
558 tryToUnlock()
559 }
560 }
562 function login() {
563 enabled = false;
564 if (LightDM.Greeter.startSessionSync()) {
565 sessionStarted();
566 greeter.hide();
567 lockscreen.hide();
568 launcher.hide();
569 }
570 enabled = true;
571 }
573 onShownChanged: {
574 if (shown) {
575 // Disable everything so that user can't swipe greeter or
576 // launcher until we get the next prompt/authenticate, which
577 // will re-enable the shell.
578 shell.enabled = false;
580 if (greeter.narrowMode) {
581 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
582 } else {
583 reset()
584 }
585 greeter.lockedApp = "";
586 greeter.forceActiveFocus();
587 }
588 }
590 Component.onCompleted: {
591 Connectivity.unlockAllModems()
592 }
594 onUnlocked: greeter.hide()
595 onSelected: {
596 // Update launcher items for new user
597 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
598 AccountsService.user = user;
599 LauncherModel.setUser(user);
600 }
602 onTease: launcher.tease()
604 Binding {
605 target: ApplicationManager
606 property: "suspended"
607 value: (greeter.shown && greeterWrapper.showProgress == 1) || lockscreen.shown
608 }
609 }
610 }
612 Connections {
613 id: callConnection
614 target: callManager
616 onHasCallsChanged: {
617 if (shell.locked && callManager.hasCalls) {
618 // We just received an incoming call while locked. The
619 // indicator will have already launched dialer-app for us, but
620 // there is a race between "hasCalls" changing and the dialer
621 // starting up. So in case we lose that race, we'll start/
622 // focus the dialer ourselves here too. Even if the indicator
623 // didn't launch the dialer for some reason (or maybe a call
624 // started via some other means), if an active call is
625 // happening, we want to be in the dialer.
626 startLockedApp("dialer-app")
627 }
628 }
629 }
631 Connections {
632 id: powerConnection
633 target: Powerd
635 onStatusChanged: {
636 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
637 !callManager.hasCalls && !edgeDemo.running) {
638 greeter.showNow()
639 }
640 }
641 }
643 function showHome() {
644 if (edgeDemo.running) {
645 return
646 }
648 if (LightDM.Greeter.active) {
649 greeter.startUnlock()
650 }
652 var animate = !LightDM.Greeter.active && !stages.shown
653 dash.setCurrentScope(0, animate, false)
654 ApplicationManager.requestFocusApplication("unity8-dash")
655 }
657 function showDash() {
658 if (greeter.hasLockedApp || // just in case user gets here
659 (!greeter.narrowMode && shell.locked)) {
660 return
661 }
663 if (greeter.shown) {
664 greeter.hideRight();
665 launcher.fadeOut();
666 }
668 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
669 ApplicationManager.requestFocusApplication("unity8-dash")
670 launcher.fadeOut();
671 }
672 }
674 Item {
675 id: overlay
676 z: 10
678 anchors.fill: parent
680 Panel {
681 id: panel
682 objectName: "panel"
683 anchors.fill: parent //because this draws indicator menus
684 indicators {
685 hides: [launcher]
686 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
687 contentEnabled: edgeDemo.panelContentEnabled
688 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
690 minimizedPanelHeight: units.gu(3)
691 expandedPanelHeight: units.gu(7)
693 indicatorsModel: visibleIndicators.model
694 }
696 VisibleIndicators {
697 id: visibleIndicators
698 // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
699 Component.onCompleted: initialise(indicatorProfile)
700 }
701 callHint {
702 greeterShown: greeter.shown || lockscreen.shown
703 }
705 property bool topmostApplicationIsFullscreen:
706 ApplicationManager.focusedApplicationId &&
707 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
709 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
710 || greeter.hasLockedApp
711 }
713 Launcher {
714 id: launcher
715 objectName: "launcher"
717 readonly property bool dashSwipe: progress > 0
719 anchors.top: parent.top
720 anchors.bottom: parent.bottom
721 width: parent.width
722 dragAreaWidth: shell.edgeSize
723 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
725 onShowDashHome: showHome()
726 onDash: showDash()
727 onDashSwipeChanged: {
728 if (dashSwipe) {
729 dash.setCurrentScope(0, false, true)
730 }
731 }
732 onLauncherApplicationSelected: {
733 if (greeter.hasLockedApp) {
734 greeter.startUnlock()
735 }
736 if (!edgeDemo.running)
737 shell.activateApplication(appId)
738 }
739 onShownChanged: {
740 if (shown) {
741 panel.indicators.hide()
742 }
743 }
744 }
746 Wizard {
747 id: wizard
748 anchors.fill: parent
749 background: shell.background
750 }
752 Rectangle {
753 id: modalNotificationBackground
755 visible: notifications.useModal && (notifications.state == "narrow")
756 color: "#000000"
757 anchors.fill: parent
758 opacity: 0.9
760 MouseArea {
761 anchors.fill: parent
762 }
763 }
765 Notifications {
766 id: notifications
768 model: NotificationBackend.Model
769 margin: units.gu(1)
771 y: topmostIsFullscreen ? 0 : panel.panelHeight
772 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
774 states: [
775 State {
776 name: "narrow"
777 when: overlay.width <= units.gu(60)
778 AnchorChanges {
779 target: notifications
780 anchors.left: parent.left
781 anchors.right: parent.right
782 }
783 },
784 State {
785 name: "wide"
786 when: overlay.width > units.gu(60)
787 AnchorChanges {
788 target: notifications
789 anchors.left: undefined
790 anchors.right: parent.right
791 }
792 PropertyChanges { target: notifications; width: units.gu(38) }
793 }
794 ]
795 }
796 }
798 Dialogs {
799 id: dialogs
800 anchors.fill: parent
801 z: overlay.z + 10
802 onPowerOffClicked: {
803 shutdownFadeOutRectangle.enabled = true;
804 shutdownFadeOutRectangle.visible = true;
805 shutdownFadeOut.start();
806 }
807 }
809 EdgeDemo {
810 id: edgeDemo
811 objectName: "edgeDemo"
812 z: dialogs.z + 10
813 paused: Powerd.status === Powerd.Off || wizard.active // Saves power
814 greeter: greeter
815 launcher: launcher
816 panel: panel
817 stages: stages
818 }
820 Connections {
821 target: SessionBroadcast
822 onShowHome: showHome()
823 }
825 Rectangle {
826 id: shutdownFadeOutRectangle
827 z: edgeDemo.z + 10
828 enabled: false
829 visible: false
830 color: "black"
831 anchors.fill: parent
832 opacity: 0.0
833 NumberAnimation on opacity {
834 id: shutdownFadeOut
835 from: 0.0
836 to: 1.0
837 onStopped: {
838 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
839 DBusUnitySessionService.Shutdown();
840 }
841 }
842 }
843 }