on fa190e6 help sign in
unity8/qml/Shell.qml
832 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 Unity.Notifications 1.0 as NotificationBackend
41import Unity.Session 0.1
42import Unity.DashCommunicator 0.1
44Item {
45 id: shell
47 // this is only here to select the width / height of the window if not running fullscreen
48 property bool tablet: false
49 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
50 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
52 property real edgeSize: units.gu(2)
53 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
54 property url background
55 readonly property real panelHeight: panel.panelHeight
57 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock
58 readonly property bool forcedUnlock: edgeDemo.running
59 onForcedUnlockChanged: if (forcedUnlock) lockscreen.hide()
61 property bool sideStageEnabled: shell.width >= units.gu(100)
62 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
64 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
65 property int failedLoginsDelayAttempts: 7 // number of failed logins
66 property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
68 property int orientation
69 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
70 onDeviceOrientationAngleChanged: {
71 if (!OrientationLock.enabled) {
72 orientation = Screen.orientation;
73 }
74 }
75 readonly property bool orientationLockEnabled: OrientationLock.enabled
76 onOrientationLockEnabledChanged: {
77 if (orientationLockEnabled) {
78 OrientationLock.savedOrientation = Screen.orientation;
79 } else {
80 orientation = Screen.orientation;
81 }
82 }
84 function activateApplication(appId) {
85 if (ApplicationManager.findApplication(appId)) {
86 ApplicationManager.requestFocusApplication(appId);
87 } else {
88 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
89 ApplicationManager.startApplication(appId, execFlags);
90 }
91 }
93 function startLockedApp(app) {
94 if (!shell.locked) {
95 console.warn("Called startLockedApp(%1) when not locked, ignoring".arg(app))
96 return
97 }
98 greeter.lockedApp = app
99 shell.activateApplication(app)
100 }
102 Binding {
103 target: LauncherModel
104 property: "applicationManager"
105 value: ApplicationManager
106 }
108 Component.onCompleted: {
109 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
110 if (ApplicationManager.count > 0) {
111 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
112 }
113 if (orientationLockEnabled) {
114 orientation = OrientationLock.savedOrientation;
115 }
116 }
118 GSettings {
119 id: backgroundSettings
120 schema.id: "org.gnome.desktop.background"
121 }
122 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
123 onGSettingsPictureChanged: {
124 shell.background = gSettingsPicture
125 }
127 VolumeControl {
128 id: volumeControl
129 }
131 DashCommunicator {
132 id: dash
133 objectName: "dashCommunicator"
134 }
136 ScreenGrabber {
137 id: screenGrabber
138 z: edgeDemo.z + 10
139 enabled: Powerd.status === Powerd.On
140 }
142 Binding {
143 target: ApplicationManager
144 property: "forceDashActive"
145 value: launcher.shown || launcher.dashSwipe
146 }
148 VolumeKeyFilter {
149 id: volumeKeyFilter
150 onVolumeDownPressed: volumeControl.volumeDown()
151 onVolumeUpPressed: volumeControl.volumeUp()
152 onBothVolumeKeysPressed: screenGrabber.capture()
153 }
155 WindowKeysFilter {
156 Keys.onPressed: {
157 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
158 dialogs.onPowerKeyPressed();
159 event.accepted = true;
160 } else {
161 volumeKeyFilter.onKeyPressed(event.key);
162 event.accepted = false;
163 }
164 }
166 Keys.onReleased: {
167 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
168 dialogs.onPowerKeyReleased();
169 event.accepted = true;
170 } else {
171 volumeKeyFilter.onKeyReleased(event.key);
172 event.accepted = false;
173 }
174 }
175 }
177 Item {
178 id: stages
179 objectName: "stages"
180 width: parent.width
181 height: parent.height
182 visible: !ApplicationManager.empty
184 Connections {
185 target: ApplicationManager
186 onFocusRequested: {
187 if (greeter.narrowMode) {
188 if (appId === "dialer-app" && callManager.hasCalls && shell.locked) {
189 // If we are in the middle of a call, make dialer lockedApp and show it.
190 // This can happen if user backs out of dialer back to greeter, then
191 // launches dialer again.
192 greeter.lockedApp = appId;
193 }
194 if (greeter.hasLockedApp) {
195 if (appId === greeter.lockedApp) {
196 lockscreen.hide() // show locked app
197 } else {
198 greeter.startUnlock() // show lockscreen if necessary
199 }
200 }
201 greeter.hide();
202 } else {
203 if (LightDM.Greeter.active) {
204 greeter.startUnlock()
205 }
206 }
207 }
209 onFocusedApplicationIdChanged: {
210 if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
211 greeter.startUnlock()
212 }
213 panel.indicators.hide();
214 }
216 onApplicationAdded: {
217 if (greeter.shown && appId != "unity8-dash") {
218 greeter.startUnlock()
219 }
220 if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
221 lockscreen.hide() // show locked app
222 }
223 launcher.hide();
224 }
225 }
227 Loader {
228 id: applicationsDisplayLoader
229 objectName: "applicationsDisplayLoader"
230 anchors.fill: parent
232 // When we have a locked app, we only want to show that one app.
233 // FIXME: do this in a less traumatic way. We currently only allow
234 // locked apps in phone mode (see FIXME in Lockscreen component in
235 // this same file). When that changes, we need to do something
236 // nicer here. But this code is currently just to prevent a
237 // theoretical attack where user enters lockedApp mode, then makes
238 // the screen larger (maybe connects to monitor) and tries to enter
239 // tablet mode.
240 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
241 source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
243 Binding {
244 target: applicationsDisplayLoader.item
245 property: "objectName"
246 value: "stage"
247 }
248 Binding {
249 target: applicationsDisplayLoader.item
250 property: "dragAreaWidth"
251 value: shell.edgeSize
252 }
253 Binding {
254 target: applicationsDisplayLoader.item
255 property: "maximizedAppTopMargin"
256 // Not just using panel.panelHeight as that changes depending on the focused app.
257 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
258 }
259 Binding {
260 target: applicationsDisplayLoader.item
261 property: "interactive"
262 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0 && !notifications.useModal
263 }
264 Binding {
265 target: applicationsDisplayLoader.item
266 property: "spreadEnabled"
267 value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
268 }
269 Binding {
270 target: applicationsDisplayLoader.item
271 property: "inverseProgress"
272 value: launcher.progress
273 }
274 Binding {
275 target: applicationsDisplayLoader.item
276 property: "orientation"
277 value: shell.orientation
278 }
279 }
280 }
282 InputMethod {
283 id: inputMethod
284 objectName: "inputMethod"
285 anchors { fill: parent; topMargin: panel.panelHeight }
286 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
287 }
289 Connections {
290 target: SurfaceManager
291 onSurfaceCreated: {
292 if (surface.type == MirSurfaceItem.InputMethod) {
293 inputMethod.surface = surface;
294 }
295 }
297 onSurfaceDestroyed: {
298 if (inputMethod.surface == surface) {
299 inputMethod.surface = null;
300 surface.parent = null;
301 }
302 if (!surface.parent) {
303 // there's no one displaying it. delete it right away
304 surface.release();
305 }
306 }
307 }
308 Connections {
309 target: SessionManager
310 onSessionStopping: {
311 if (!session.parentSession && !session.application) {
312 // nothing is using it. delete it right away
313 session.release();
314 }
315 }
316 }
318 Lockscreen {
319 id: lockscreen
320 objectName: "lockscreen"
322 hides: [launcher, panel.indicators]
323 shown: false
324 enabled: true
325 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
326 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
327 y: panel.panelHeight
328 visible: required
329 width: parent.width
330 height: parent.height - panel.panelHeight
331 background: shell.background
332 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
333 minPinLength: 4
334 maxPinLength: 4
336 // FIXME: We *should* show emergency dialer if there is a SIM present,
337 // regardless of whether the side stage is enabled. But right now,
338 // the assumption is that narrow screens are phones which have SIMs
339 // and wider screens are tablets which don't. When we do allow this
340 // on devices with a side stage and a SIM, work should be done to
341 // ensure that the main stage is disabled while the dialer is present
342 // in the side stage. See the FIXME in the stage loader in this file.
343 showEmergencyCallButton: !shell.sideStageEnabled
345 onEntered: LightDM.Greeter.respond(passphrase);
346 onCancel: greeter.show()
347 onEmergencyCall: startLockedApp("dialer-app")
349 onShownChanged: if (shown) greeter.lockedApp = ""
351 function maybeShow() {
352 if (!shell.forcedUnlock) {
353 show()
354 }
355 }
357 Timer {
358 id: forcedDelayTimer
359 interval: 1000 * 60
360 onTriggered: {
361 if (lockscreen.delayMinutes > 0) {
362 lockscreen.delayMinutes -= 1
363 if (lockscreen.delayMinutes > 0) {
364 start() // go again
365 }
366 }
367 }
368 }
370 Component.onCompleted: {
371 if (greeter.narrowMode) {
372 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
373 }
374 }
375 }
377 Connections {
378 target: LightDM.Greeter
380 onShowGreeter: greeter.show()
381 onHideGreeter: greeter.login()
383 onShowPrompt: {
384 shell.enabled = true;
385 if (!LightDM.Greeter.active) {
386 return; // could happen if hideGreeter() comes in before we prompt
387 }
388 if (greeter.narrowMode) {
389 if (isDefaultPrompt) {
390 if (lockscreen.alphaNumeric) {
391 lockscreen.infoText = i18n.tr("Enter passphrase")
392 lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase") + "\n" +
393 i18n.tr("Please re-enter")
394 } else {
395 lockscreen.infoText = i18n.tr("Enter passcode")
396 lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
397 }
398 } else {
399 lockscreen.infoText = i18n.tr("Enter %1").arg(text.toLowerCase())
400 lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
401 }
403 lockscreen.maybeShow();
404 }
405 }
407 onPromptlessChanged: {
408 if (!LightDM.Greeter.active) {
409 return; // could happen if hideGreeter() comes in before we prompt
410 }
411 if (greeter.narrowMode) {
412 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
413 lockscreen.hide()
414 } else {
415 lockscreen.reset();
416 lockscreen.maybeShow();
417 }
418 }
419 }
421 onAuthenticationComplete: {
422 shell.enabled = true;
423 if (LightDM.Greeter.authenticated) {
424 AccountsService.failedLogins = 0
425 }
426 // Else only penalize user for a failed login if they actually were
427 // prompted for a password. We do this below after the promptless
428 // early exit.
430 if (LightDM.Greeter.promptless) {
431 return;
432 }
434 if (LightDM.Greeter.authenticated) {
435 greeter.login();
436 } else {
437 AccountsService.failedLogins++
438 if (maxFailedLogins >= 2) { // require at least a warning
439 if (AccountsService.failedLogins === maxFailedLogins - 1) {
440 var title = lockscreen.alphaNumeric ?
441 i18n.tr("Sorry, incorrect passphrase.") :
442 i18n.tr("Sorry, incorrect passcode.")
443 var text = i18n.tr("This will be your last attempt.") + " " +
444 (lockscreen.alphaNumeric ?
445 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
446 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
447 lockscreen.showInfoPopup(title, text)
448 } else if (AccountsService.failedLogins >= maxFailedLogins) {
449 SystemImage.factoryReset() // Ouch!
450 }
451 }
452 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
453 lockscreen.delayMinutes = failedLoginsDelayMinutes
454 forcedDelayTimer.start()
455 }
457 lockscreen.clear(true);
458 if (greeter.narrowMode) {
459 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
460 }
461 }
462 }
463 }
465 Binding {
466 target: LightDM.Greeter
467 property: "active"
468 value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
469 }
471 Rectangle {
472 anchors.fill: parent
473 color: "black"
474 opacity: greeterWrapper.showProgress * 0.8
475 }
477 Item {
478 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
479 id: greeterWrapper
480 objectName: "greeterWrapper"
481 x: greeter.narrowMode ? launcher.progress : 0
482 y: panel.panelHeight
483 width: parent.width
484 height: parent.height - panel.panelHeight
486 Behavior on x {
487 enabled: !launcher.dashSwipe
488 StandardAnimation {}
489 }
491 property bool fullyShown: showProgress === 1.0
492 onFullyShownChanged: {
493 // Wait until the greeter is completely covering lockscreen before resetting it.
494 if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
495 lockscreen.reset();
496 lockscreen.maybeShow();
497 }
498 }
500 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
501 onShowProgressChanged: {
502 if (showProgress === 0) {
503 if ((LightDM.Greeter.promptless && LightDM.Greeter.authenticated) || shell.forcedUnlock) {
504 greeter.login()
505 } else if (greeter.narrowMode) {
506 lockscreen.clear(false) // to reset focus if necessary
507 }
508 }
509 }
511 Greeter {
512 id: greeter
513 objectName: "greeter"
515 signal sessionStarted() // helpful for tests
517 property string lockedApp: ""
518 property bool hasLockedApp: lockedApp !== ""
520 available: true
521 hides: [launcher, panel.indicators]
522 shown: true
523 loadContent: required || lockscreen.required // keeps content in memory for quick show()
525 locked: shell.locked
527 defaultBackground: shell.background
529 width: parent.width
530 height: parent.height
532 dragHandleWidth: shell.edgeSize
534 function startUnlock() {
535 if (narrowMode) {
536 if (!LightDM.Greeter.authenticated) {
537 lockscreen.maybeShow()
538 }
539 hide()
540 } else {
541 show()
542 tryToUnlock()
543 }
544 }
546 function login() {
547 enabled = false;
548 if (LightDM.Greeter.startSessionSync()) {
549 sessionStarted();
550 greeter.hide();
551 lockscreen.hide();
552 launcher.hide();
553 }
554 enabled = true;
555 }
557 onShownChanged: {
558 if (shown) {
559 // Disable everything so that user can't swipe greeter or
560 // launcher until we get first prompt/authenticate, which
561 // will re-enable the shell.
562 shell.enabled = false;
564 if (greeter.narrowMode) {
565 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
566 } else {
567 reset()
568 }
569 greeter.lockedApp = "";
570 greeter.forceActiveFocus();
571 }
572 }
574 Component.onCompleted: {
575 Connectivity.unlockAllModems()
576 }
578 onUnlocked: greeter.hide()
579 onSelected: {
580 // Update launcher items for new user
581 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
582 AccountsService.user = user;
583 LauncherModel.setUser(user);
584 }
586 onTease: launcher.tease()
588 Binding {
589 target: ApplicationManager
590 property: "suspended"
591 value: greeter.shown && greeterWrapper.showProgress == 1
592 }
593 }
594 }
596 Connections {
597 id: callConnection
598 target: callManager
600 onHasCallsChanged: {
601 if (shell.locked && callManager.hasCalls) {
602 // We just received an incoming call while locked. The
603 // indicator will have already launched dialer-app for us, but
604 // there is a race between "hasCalls" changing and the dialer
605 // starting up. So in case we lose that race, we'll start/
606 // focus the dialer ourselves here too. Even if the indicator
607 // didn't launch the dialer for some reason (or maybe a call
608 // started via some other means), if an active call is
609 // happening, we want to be in the dialer.
610 startLockedApp("dialer-app")
611 }
612 }
613 }
615 Connections {
616 id: powerConnection
617 target: Powerd
619 onStatusChanged: {
620 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
621 !callManager.hasCalls && !edgeDemo.running) {
622 greeter.showNow()
623 }
624 }
625 }
627 function showHome() {
628 if (edgeDemo.running) {
629 return
630 }
632 if (LightDM.Greeter.active) {
633 greeter.startUnlock()
634 }
636 var animate = !LightDM.Greeter.active && !stages.shown
637 dash.setCurrentScope(0, animate, false)
638 ApplicationManager.requestFocusApplication("unity8-dash")
639 }
641 function showDash() {
642 if (greeter.hasLockedApp || // just in case user gets here
643 (!greeter.narrowMode && shell.locked)) {
644 return
645 }
647 if (greeter.shown) {
648 greeter.hideRight();
649 launcher.fadeOut();
650 }
652 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
653 ApplicationManager.requestFocusApplication("unity8-dash")
654 launcher.fadeOut();
655 }
656 }
658 Item {
659 id: overlay
660 z: 10
662 anchors.fill: parent
664 Panel {
665 id: panel
666 objectName: "panel"
667 anchors.fill: parent //because this draws indicator menus
668 indicators {
669 hides: [launcher]
670 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
671 contentEnabled: edgeDemo.panelContentEnabled
672 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
674 minimizedPanelHeight: units.gu(3)
675 expandedPanelHeight: units.gu(7)
677 indicatorsModel: visibleIndicators.model
678 }
680 VisibleIndicators {
681 id: visibleIndicators
682 // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
683 Component.onCompleted: initialise(indicatorProfile)
684 }
685 callHint {
686 greeterShown: greeter.shown || lockscreen.shown
687 }
689 property bool topmostApplicationIsFullscreen:
690 ApplicationManager.focusedApplicationId &&
691 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
693 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
694 || greeter.hasLockedApp
695 }
697 Launcher {
698 id: launcher
699 objectName: "launcher"
701 readonly property bool dashSwipe: progress > 0
703 anchors.top: parent.top
704 anchors.bottom: parent.bottom
705 width: parent.width
706 dragAreaWidth: shell.edgeSize
707 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
709 onShowDashHome: showHome()
710 onDash: showDash()
711 onDashSwipeChanged: {
712 if (dashSwipe) {
713 dash.setCurrentScope(0, false, true)
714 }
715 }
716 onLauncherApplicationSelected: {
717 if (greeter.hasLockedApp) {
718 greeter.startUnlock()
719 }
720 if (!edgeDemo.running)
721 shell.activateApplication(appId)
722 }
723 onShownChanged: {
724 if (shown) {
725 panel.indicators.hide()
726 }
727 }
728 }
730 Rectangle {
731 id: modalNotificationBackground
733 visible: notifications.useModal && (notifications.state == "narrow")
734 color: "#000000"
735 anchors.fill: parent
736 opacity: 0.9
738 MouseArea {
739 anchors.fill: parent
740 }
741 }
743 Notifications {
744 id: notifications
746 model: NotificationBackend.Model
747 margin: units.gu(1)
749 y: topmostIsFullscreen ? 0 : panel.panelHeight
750 width: parent.width
751 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
753 states: [
754 State {
755 name: "narrow"
756 when: overlay.width <= units.gu(60)
757 AnchorChanges { target: notifications; anchors.left: parent.left }
758 },
759 State {
760 name: "wide"
761 when: overlay.width > units.gu(60)
762 AnchorChanges { target: notifications; anchors.left: undefined }
763 PropertyChanges { target: notifications; width: units.gu(38) }
764 }
765 ]
766 }
767 }
769 Dialogs {
770 id: dialogs
771 anchors.fill: parent
772 z: overlay.z + 10
773 onPowerOffClicked: {
774 shutdownFadeOutRectangle.enabled = true;
775 shutdownFadeOutRectangle.visible = true;
776 shutdownFadeOut.start();
777 }
778 }
780 Label {
781 id: alphaDisclaimerLabel
782 anchors.centerIn: parent
783 visible: ApplicationManager.fake ? ApplicationManager.fake : false
784 z: dialogs.z + 10
785 text: "EARLY ALPHA\nNOT READY FOR USE"
786 color: "lightgrey"
787 opacity: 0.2
788 font.weight: Font.Black
789 horizontalAlignment: Text.AlignHCenter
790 verticalAlignment: Text.AlignVCenter
791 fontSizeMode: Text.Fit
792 rotation: -45
793 scale: Math.min(parent.width, parent.height) / width
794 }
796 EdgeDemo {
797 id: edgeDemo
798 objectName: "edgeDemo"
799 z: alphaDisclaimerLabel.z + 10
800 paused: Powerd.status === Powerd.Off // Saves power
801 greeter: greeter
802 launcher: launcher
803 panel: panel
804 stages: stages
805 }
807 Connections {
808 target: SessionBroadcast
809 onShowHome: showHome()
810 }
812 Rectangle {
813 id: shutdownFadeOutRectangle
814 z: edgeDemo.z + 10
815 enabled: false
816 visible: false
817 color: "black"
818 anchors.fill: parent
819 opacity: 0.0
820 NumberAnimation on opacity {
821 id: shutdownFadeOut
822 from: 0.0
823 to: 1.0
824 onStopped: {
825 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
826 DBusUnitySessionService.Shutdown();
827 }
828 }
829 }
830 }