on a258c2d help sign in
unity8/qml/Shell.qml
858 lines 30 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 ScreenGrabber {
158 id: screenGrabber
159 z: edgeDemo.z + 10
160 enabled: Powerd.status === Powerd.On
161 }
163 Binding {
164 target: ApplicationManager
165 property: "forceDashActive"
166 value: launcher.shown || launcher.dashSwipe
167 }
169 VolumeKeyFilter {
170 id: volumeKeyFilter
171 onVolumeDownPressed: volumeControl.volumeDown()
172 onVolumeUpPressed: volumeControl.volumeUp()
173 onBothVolumeKeysPressed: screenGrabber.capture()
174 }
176 WindowKeysFilter {
177 Keys.onPressed: {
178 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
179 dialogs.onPowerKeyPressed();
180 event.accepted = true;
181 } else {
182 volumeKeyFilter.onKeyPressed(event.key);
183 event.accepted = false;
184 }
185 }
187 Keys.onReleased: {
188 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
189 dialogs.onPowerKeyReleased();
190 event.accepted = true;
191 } else {
192 volumeKeyFilter.onKeyReleased(event.key);
193 event.accepted = false;
194 }
195 }
196 }
198 Item {
199 id: stages
200 objectName: "stages"
201 width: parent.width
202 height: parent.height
203 visible: !ApplicationManager.empty
205 Connections {
206 target: ApplicationManager
207 onFocusRequested: {
208 if (greeter.narrowMode) {
209 if (appId === "dialer-app" && callManager.hasCalls && shell.locked) {
210 // If we are in the middle of a call, make dialer lockedApp and show it.
211 // This can happen if user backs out of dialer back to greeter, then
212 // launches dialer again.
213 greeter.lockedApp = appId;
214 }
215 if (greeter.hasLockedApp) {
216 if (appId === greeter.lockedApp) {
217 lockscreen.hide() // show locked app
218 } else {
219 greeter.startUnlock() // show lockscreen if necessary
220 }
221 }
222 greeter.hide();
223 } else {
224 if (LightDM.Greeter.active) {
225 greeter.startUnlock()
226 }
227 }
228 }
230 onFocusedApplicationIdChanged: {
231 if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
232 greeter.startUnlock()
233 }
234 panel.indicators.hide();
235 }
237 onApplicationAdded: {
238 if (greeter.shown && appId != "unity8-dash") {
239 greeter.startUnlock()
241 // If this happens on first boot, we may be in edge
242 // tutorial or wizard while receiving a call. But a call
243 // is more important than wizard so just bail out of those.
244 if (edgeDemo.running) {
245 edgeDemo.hideEdgeDemos();
246 wizard.hide();
247 }
248 }
249 if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
250 lockscreen.hide() // show locked app
251 }
252 launcher.hide();
253 }
254 }
256 Loader {
257 id: applicationsDisplayLoader
258 objectName: "applicationsDisplayLoader"
259 anchors.fill: parent
261 // When we have a locked app, we only want to show that one app.
262 // FIXME: do this in a less traumatic way. We currently only allow
263 // locked apps in phone mode (see FIXME in Lockscreen component in
264 // this same file). When that changes, we need to do something
265 // nicer here. But this code is currently just to prevent a
266 // theoretical attack where user enters lockedApp mode, then makes
267 // the screen larger (maybe connects to monitor) and tries to enter
268 // tablet mode.
269 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
270 source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
272 Binding {
273 target: applicationsDisplayLoader.item
274 property: "objectName"
275 value: "stage"
276 }
277 Binding {
278 target: applicationsDisplayLoader.item
279 property: "dragAreaWidth"
280 value: shell.edgeSize
281 }
282 Binding {
283 target: applicationsDisplayLoader.item
284 property: "maximizedAppTopMargin"
285 // Not just using panel.panelHeight as that changes depending on the focused app.
286 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
287 }
288 Binding {
289 target: applicationsDisplayLoader.item
290 property: "interactive"
291 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0 && !notifications.useModal
292 }
293 Binding {
294 target: applicationsDisplayLoader.item
295 property: "spreadEnabled"
296 value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
297 }
298 Binding {
299 target: applicationsDisplayLoader.item
300 property: "inverseProgress"
301 value: launcher.progress
302 }
303 Binding {
304 target: applicationsDisplayLoader.item
305 property: "orientation"
306 value: shell.orientation
307 }
308 }
309 }
311 InputMethod {
312 id: inputMethod
313 objectName: "inputMethod"
314 anchors { fill: parent; topMargin: panel.panelHeight }
315 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
316 }
318 Connections {
319 target: SurfaceManager
320 onSurfaceCreated: {
321 if (surface.type == MirSurfaceItem.InputMethod) {
322 inputMethod.surface = surface;
323 }
324 }
326 onSurfaceDestroyed: {
327 if (inputMethod.surface == surface) {
328 inputMethod.surface = null;
329 surface.parent = null;
330 }
331 if (!surface.parent) {
332 // there's no one displaying it. delete it right away
333 surface.release();
334 }
335 }
336 }
337 Connections {
338 target: SessionManager
339 onSessionStopping: {
340 if (!session.parentSession && !session.application) {
341 // nothing is using it. delete it right away
342 session.release();
343 }
344 }
345 }
347 Lockscreen {
348 id: lockscreen
349 objectName: "lockscreen"
351 hides: [launcher, panel.indicators]
352 shown: false
353 enabled: true
354 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
355 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
356 y: panel.panelHeight
357 visible: required
358 width: parent.width
359 height: parent.height - panel.panelHeight
360 background: shell.background
361 darkenBackground: 0.4
362 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
363 minPinLength: 4
364 maxPinLength: 4
366 property string promptText
367 infoText: promptText !== "" ? i18n.tr("Enter %1").arg(promptText) :
368 alphaNumeric ? i18n.tr("Enter passphrase") :
369 i18n.tr("Enter passcode")
370 errorText: promptText !== "" ? i18n.tr("Sorry, incorrect %1").arg(promptText) :
371 alphaNumeric ? i18n.tr("Sorry, incorrect passphrase") + "\n" +
372 i18n.tr("Please re-enter") :
373 i18n.tr("Sorry, incorrect passcode")
375 // FIXME: We *should* show emergency dialer if there is a SIM present,
376 // regardless of whether the side stage is enabled. But right now,
377 // the assumption is that narrow screens are phones which have SIMs
378 // and wider screens are tablets which don't. When we do allow this
379 // on devices with a side stage and a SIM, work should be done to
380 // ensure that the main stage is disabled while the dialer is present
381 // in the side stage. See the FIXME in the stage loader in this file.
382 showEmergencyCallButton: !shell.sideStageEnabled
384 onEntered: LightDM.Greeter.respond(passphrase);
385 onCancel: greeter.show()
386 onEmergencyCall: startLockedApp("dialer-app")
388 onShownChanged: if (shown) greeter.lockedApp = ""
390 function maybeShow() {
391 if (!shell.forcedUnlock) {
392 show()
393 }
394 }
396 Timer {
397 id: forcedDelayTimer
398 interval: 1000 * 60
399 onTriggered: {
400 if (lockscreen.delayMinutes > 0) {
401 lockscreen.delayMinutes -= 1
402 if (lockscreen.delayMinutes > 0) {
403 start() // go again
404 }
405 }
406 }
407 }
409 Component.onCompleted: {
410 if (greeter.narrowMode) {
411 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
412 }
413 }
414 }
416 Connections {
417 target: LightDM.Greeter
419 onShowGreeter: greeter.show()
420 onHideGreeter: greeter.login()
422 onShowPrompt: {
423 shell.enabled = true;
424 if (!LightDM.Greeter.active) {
425 return; // could happen if hideGreeter() comes in before we prompt
426 }
427 if (greeter.narrowMode) {
428 lockscreen.promptText = isDefaultPrompt ? "" : text.toLowerCase();
429 lockscreen.maybeShow();
430 }
431 }
433 onPromptlessChanged: {
434 if (!LightDM.Greeter.active) {
435 return; // could happen if hideGreeter() comes in before we prompt
436 }
437 if (greeter.narrowMode) {
438 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
439 lockscreen.hide()
440 } else {
441 lockscreen.reset();
442 lockscreen.maybeShow();
443 }
444 }
445 }
447 onAuthenticationComplete: {
448 shell.enabled = true;
449 if (LightDM.Greeter.authenticated) {
450 AccountsService.failedLogins = 0
451 }
452 // Else only penalize user for a failed login if they actually were
453 // prompted for a password. We do this below after the promptless
454 // early exit.
456 if (LightDM.Greeter.promptless) {
457 return;
458 }
460 if (LightDM.Greeter.authenticated) {
461 greeter.login();
462 } else {
463 AccountsService.failedLogins++
464 if (maxFailedLogins >= 2) { // require at least a warning
465 if (AccountsService.failedLogins === maxFailedLogins - 1) {
466 var title = lockscreen.alphaNumeric ?
467 i18n.tr("Sorry, incorrect passphrase.") :
468 i18n.tr("Sorry, incorrect passcode.")
469 var text = i18n.tr("This will be your last attempt.") + " " +
470 (lockscreen.alphaNumeric ?
471 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
472 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
473 lockscreen.showInfoPopup(title, text)
474 } else if (AccountsService.failedLogins >= maxFailedLogins) {
475 SystemImage.factoryReset() // Ouch!
476 }
477 }
478 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
479 lockscreen.delayMinutes = failedLoginsDelayMinutes
480 forcedDelayTimer.start()
481 }
483 lockscreen.clear(true);
484 if (greeter.narrowMode) {
485 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
486 }
487 }
488 }
489 }
491 Binding {
492 target: LightDM.Greeter
493 property: "active"
494 value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
495 }
497 Rectangle {
498 anchors.fill: parent
499 color: "black"
500 opacity: greeterWrapper.showProgress * 0.8
501 }
503 Item {
504 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
505 id: greeterWrapper
506 objectName: "greeterWrapper"
507 x: (greeter.narrowMode && greeter.showProgress > 0) ? launcher.progress : 0
508 y: panel.panelHeight
509 width: parent.width
510 height: parent.height - panel.panelHeight
512 Behavior on x {
513 enabled: !launcher.dashSwipe
514 StandardAnimation {}
515 }
517 property bool fullyShown: showProgress === 1.0
518 onFullyShownChanged: {
519 // Wait until the greeter is completely covering lockscreen before resetting it.
520 if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
521 lockscreen.reset();
522 lockscreen.maybeShow();
523 }
524 }
526 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
527 onShowProgressChanged: {
528 if (showProgress === 0) {
529 if ((LightDM.Greeter.promptless && LightDM.Greeter.authenticated) || shell.forcedUnlock) {
530 greeter.login()
531 } else if (greeter.narrowMode) {
532 lockscreen.clear(false) // to reset focus if necessary
533 }
534 }
535 }
537 Greeter {
538 id: greeter
539 objectName: "greeter"
541 signal sessionStarted() // helpful for tests
543 property string lockedApp: ""
544 property bool hasLockedApp: lockedApp !== ""
546 locked: shell.locked
548 background: shell.background
550 width: parent.width
551 height: parent.height
554 // avoid overlapping with Launcher's edge drag area
555 // FIXME: Fix TouchRegistry & friends and remove this workaround
556 // Issue involves launcher's DDA getting disabled on a long
557 // left-edge drag
558 dragHandleLeftMargin: launcher.dragAreaWidth + 1
560 function startUnlock() {
561 if (narrowMode) {
562 if (!LightDM.Greeter.authenticated) {
563 lockscreen.maybeShow()
564 }
565 hide()
566 } else {
567 show()
568 tryToUnlock()
569 }
570 }
572 function login() {
573 enabled = false;
574 if (LightDM.Greeter.startSessionSync()) {
575 sessionStarted();
576 greeter.hide();
577 lockscreen.hide();
578 launcher.hide();
579 }
580 enabled = true;
581 }
583 onShownChanged: {
584 if (shown) {
585 launcher.hide();
586 panel.indicators.hide();
588 // Disable everything so that user can't swipe greeter or
589 // launcher until we get the next prompt/authenticate, which
590 // will re-enable the shell.
591 shell.enabled = false;
593 if (greeter.narrowMode) {
594 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
595 } else {
596 reset()
597 }
598 greeter.lockedApp = "";
599 greeter.forceActiveFocus();
600 }
601 }
603 Component.onCompleted: {
604 Connectivity.unlockAllModems()
605 }
607 onUnlocked: greeter.hide()
608 onSelected: {
609 // Update launcher items for new user
610 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
611 AccountsService.user = user;
612 LauncherModel.setUser(user);
613 }
615 onTapped: launcher.tease()
617 Binding {
618 target: ApplicationManager
619 property: "suspended"
620 value: (greeter.shown && greeterWrapper.showProgress == 1) || lockscreen.shown
621 }
622 }
623 }
625 Connections {
626 id: callConnection
627 target: callManager
629 onHasCallsChanged: {
630 if (shell.locked && callManager.hasCalls) {
631 // We just received an incoming call while locked. The
632 // indicator will have already launched dialer-app for us, but
633 // there is a race between "hasCalls" changing and the dialer
634 // starting up. So in case we lose that race, we'll start/
635 // focus the dialer ourselves here too. Even if the indicator
636 // didn't launch the dialer for some reason (or maybe a call
637 // started via some other means), if an active call is
638 // happening, we want to be in the dialer.
639 startLockedApp("dialer-app")
640 }
641 }
642 }
644 Connections {
645 id: powerConnection
646 target: Powerd
648 onStatusChanged: {
649 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
650 !callManager.hasCalls && !edgeDemo.running) {
651 greeter.showNow()
652 }
653 }
654 }
656 function showHome() {
657 if (edgeDemo.running) {
658 return
659 }
661 if (LightDM.Greeter.active) {
662 greeter.startUnlock()
663 }
665 var animate = !LightDM.Greeter.active && !stages.shown
666 dash.setCurrentScope(0, animate, false)
667 ApplicationManager.requestFocusApplication("unity8-dash")
668 }
670 function showDash() {
671 if (greeter.hasLockedApp || // just in case user gets here
672 (!greeter.narrowMode && shell.locked)) {
673 return
674 }
676 if (greeter.shown) {
677 greeter.hideRight();
678 launcher.fadeOut();
679 }
681 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
682 ApplicationManager.requestFocusApplication("unity8-dash")
683 launcher.fadeOut();
684 }
685 }
687 Item {
688 id: overlay
689 z: 10
691 anchors.fill: parent
693 Panel {
694 id: panel
695 objectName: "panel"
696 anchors.fill: parent //because this draws indicator menus
697 indicators {
698 hides: [launcher]
699 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
700 contentEnabled: edgeDemo.panelContentEnabled
701 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
703 minimizedPanelHeight: units.gu(3)
704 expandedPanelHeight: units.gu(7)
706 indicatorsModel: visibleIndicators.model
707 }
709 VisibleIndicators {
710 id: visibleIndicators
711 // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
712 Component.onCompleted: initialise(indicatorProfile)
713 }
714 callHint {
715 greeterShown: greeter.shown || lockscreen.shown
716 }
718 property bool topmostApplicationIsFullscreen:
719 ApplicationManager.focusedApplicationId &&
720 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
722 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
723 || greeter.hasLockedApp
724 }
726 Launcher {
727 id: launcher
728 objectName: "launcher"
730 readonly property bool dashSwipe: progress > 0
732 anchors.top: parent.top
733 anchors.bottom: parent.bottom
734 width: parent.width
735 dragAreaWidth: shell.edgeSize
736 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
738 onShowDashHome: showHome()
739 onDash: showDash()
740 onDashSwipeChanged: {
741 if (dashSwipe) {
742 dash.setCurrentScope(0, false, true)
743 }
744 }
745 onLauncherApplicationSelected: {
746 if (greeter.hasLockedApp) {
747 greeter.startUnlock()
748 }
749 if (!edgeDemo.running)
750 shell.activateApplication(appId)
751 }
752 onShownChanged: {
753 if (shown) {
754 panel.indicators.hide()
755 }
756 }
757 }
759 Wizard {
760 id: wizard
761 anchors.fill: parent
762 background: shell.background
763 }
765 Rectangle {
766 id: modalNotificationBackground
768 visible: notifications.useModal && (notifications.state == "narrow")
769 color: "#000000"
770 anchors.fill: parent
771 opacity: 0.9
773 MouseArea {
774 anchors.fill: parent
775 }
776 }
778 Notifications {
779 id: notifications
781 model: NotificationBackend.Model
782 margin: units.gu(1)
784 y: topmostIsFullscreen ? 0 : panel.panelHeight
785 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
787 states: [
788 State {
789 name: "narrow"
790 when: overlay.width <= units.gu(60)
791 AnchorChanges {
792 target: notifications
793 anchors.left: parent.left
794 anchors.right: parent.right
795 }
796 },
797 State {
798 name: "wide"
799 when: overlay.width > units.gu(60)
800 AnchorChanges {
801 target: notifications
802 anchors.left: undefined
803 anchors.right: parent.right
804 }
805 PropertyChanges { target: notifications; width: units.gu(38) }
806 }
807 ]
808 }
809 }
811 Dialogs {
812 id: dialogs
813 anchors.fill: parent
814 z: overlay.z + 10
815 onPowerOffClicked: {
816 shutdownFadeOutRectangle.enabled = true;
817 shutdownFadeOutRectangle.visible = true;
818 shutdownFadeOut.start();
819 }
820 }
822 EdgeDemo {
823 id: edgeDemo
824 objectName: "edgeDemo"
825 z: dialogs.z + 10
826 paused: Powerd.status === Powerd.Off || wizard.active // Saves power
827 greeter: greeter
828 launcher: launcher
829 panel: panel
830 stages: stages
831 }
833 Connections {
834 target: SessionBroadcast
835 onShowHome: showHome()
836 }
838 Rectangle {
839 id: shutdownFadeOutRectangle
840 z: edgeDemo.z + 10
841 enabled: false
842 visible: false
843 color: "black"
844 anchors.fill: parent
845 opacity: 0.0
846 NumberAnimation on opacity {
847 id: shutdownFadeOut
848 from: 0.0
849 to: 1.0
850 onStopped: {
851 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
852 DBusUnitySessionService.Shutdown();
853 }
854 }
855 }
856 }