on f7199c3 help sign in
unity8/qml/Shell.qml
829 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 AccountsService 0.1
19import GSettings 1.0
20import Unity.Application 0.1
21import Ubuntu.Components 0.1
22import Ubuntu.Gestures 0.1
23import Unity.Launcher 0.1
24import LightDM 0.1 as LightDM
25import Powerd 0.1
26import SessionBroadcast 0.1
27import "Dash"
28import "Greeter"
29import "Launcher"
30import "Panel"
31import "Hud"
32import "Components"
33import "Bottombar"
34import "SideStage"
35import "Notifications"
36import Unity.Notifications 1.0 as NotificationBackend
38FocusScope {
39 id: shell
41 // this is only here to select the width / height of the window if not running fullscreen
42 property bool tablet: false
43 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
44 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
46 property real edgeSize: units.gu(2)
47 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
48 property url background
49 readonly property real panelHeight: panel.panelHeight
51 property bool dashShown: dash.shown
52 property bool stageScreenshotsReady: {
53 if (sideStage.shown) {
54 if (mainStage.applications.count > 0) {
55 return mainStage.usingScreenshots && sideStage.usingScreenshots;
56 } else {
57 return sideStage.usingScreenshots;
58 }
59 } else {
60 return mainStage.usingScreenshots;
61 }
62 }
64 property var applicationManager: ApplicationManagerWrapper {}
66 Binding {
67 target: LauncherModel
68 property: "applicationManager"
69 value: ApplicationManager
70 }
72 Component.onCompleted: {
73 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
75 applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
77 // FIXME: if application focused before shell starts, shell draws on top of it only.
78 // We should detect already running applications on shell start and bring them to the front.
79 applicationManager.unfocusCurrentApplication();
81 applicationManager.setMainStageAppRect(mainStageAppRect);
82 applicationManager.setSideStageAppRect(sideStageAppRect);
83 }
85 readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
86 || !!applicationManager.sideStageFocusedApplication
87 // Used for autopilot testing.
88 readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
90 readonly property bool fullscreenMode: {
91 if (greeter.shown || lockscreen.shown) {
92 return false;
93 } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
94 return mainStage.switchingFromFullscreenToFullscreen;
95 } else if (applicationManager.mainStageFocusedApplication) {
96 return applicationManager.mainStageFocusedApplication.fullscreen;
97 } else {
98 return false;
99 }
100 }
102 function activateApplication(appId, argument) {
103 if (applicationManager) {
104 // For newly started applications, as it takes them time to draw their first frame
105 // we add a delay before we hide the animation screenshots to compensate.
106 var addDelay = !applicationManager.getApplicationFromDesktopFile(appId);
108 var application;
109 application = applicationManager.activateApplication(appId, argument);
110 if (application == null) {
111 return;
112 }
113 if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
114 mainStage.activateApplication(appId, addDelay);
115 } else {
116 sideStage.activateApplication(appId, addDelay);
117 }
118 stages.show();
119 }
120 }
122 GSettings {
123 id: backgroundSettings
124 schema.id: "org.gnome.desktop.background"
125 }
126 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
127 onGSettingsPictureChanged: {
128 shell.background = gSettingsPicture
129 }
131 VolumeControl {
132 id: volumeControl
133 }
135 Keys.onVolumeUpPressed: volumeControl.volumeUp()
136 Keys.onVolumeDownPressed: volumeControl.volumeDown()
138 Item {
139 id: underlay
140 objectName: "underlay"
141 anchors.fill: parent
143 // Whether the underlay is fully covered by opaque UI elements.
144 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
146 readonly property bool mainStageApplicationRunning: mainStage.applications && mainStage.applications.count > 0
147 readonly property bool sideStageApplicationRunning: sideStage.applications && sideStage.applications.count > 0
149 // Whether the user should see the topmost application surface (if there's one at all).
150 readonly property bool mainStageApplicationShown: mainStageApplicationRunning && !stages.fullyHidden
151 && !mainStage.usingScreenshots // but want sideStage animating over app surface
155 // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
156 // through the translucent parts of the shell surface.
157 visible: !fullyCovered && !mainStageApplicationShown
159 Item {
160 id: underlayClipper
161 clip: !parent.mainStageApplicationShown && parent.sideStageApplicationRunning && stagesOuterContainer.showProgress > 0
162 width: {
163 if (clip) {
164 var w = parent.width - sideStage.width
165 w += stagesOuterContainer.x + stages.x
166 return Math.min(w, parent.width);
167 } else {
168 return parent.width;
169 }
170 }
171 height: parent.height
173 Rectangle {
174 width: underlay.width
175 height: underlay.height
176 color: "black"
177 opacity: dash.disappearingAnimationProgress
178 }
180 Image {
181 anchors.fill: dash
182 source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
183 fillMode: Image.PreserveAspectCrop
184 horizontalAlignment: Image.AlignRight
185 verticalAlignment: Image.AlignTop
186 }
188 Dash {
189 id: dash
190 objectName: "dash"
192 available: !greeter.shown && !lockscreen.shown
193 hides: [stages, launcher, panel.indicators]
194 shown: disappearingAnimationProgress !== 1.0
195 enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
196 // FIXME: unfocus all applications when going back to the dash
197 onEnabledChanged: {
198 if (enabled) {
199 shell.applicationManager.unfocusCurrentApplication()
200 }
201 }
203 width: underlay.width
204 height: underlay.height - y
205 y: panel.panelHeight
207 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
208 opacity: 1.0 - disappearingAnimationProgress
209 property real disappearingAnimationProgress: {
210 if (greeter.shown) {
211 return greeter.showProgress;
212 } else {
213 if (underlayClipper.clip)
214 return stagesOuterContainer.showProgress * 0.5;
215 else
216 return stagesOuterContainer.showProgress;
217 }
218 }
220 // FIXME: only necessary because stagesOuterContainer.showProgress and
221 // greeterRevealer.animatedProgress are not animated
222 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
223 }
225 AbstractButton {
226 enabled: stagesOuterContainer.showProgress == 1
227 anchors.fill: parent
228 onClicked: {
229 stages.hide();
230 }
231 }
232 }
233 }
235 Item {
236 id: stagesOuterContainer
238 width: parent.width
239 height: parent.height
240 x: launcher.progress
241 Behavior on x {SmoothedAnimation{velocity: 600}}
243 property real showProgress:
244 MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
246 Showable {
247 id: stages
248 objectName: "stages"
250 x: width
252 property bool fullyShown: shown && x == 0 && parent.x == 0
253 property bool fullyHidden: !shown && x == width
254 available: !greeter.shown
255 hides: [panel.indicators]
256 shown: false
257 opacity: 1.0
258 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
259 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
261 width: parent.width
262 height: parent.height
264 // close the stages when no focused application remains
265 Connections {
266 target: shell.applicationManager
267 onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
268 onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
269 ignoreUnknownSignals: true
270 }
272 function closeIfNoApplications() {
273 if (!shell.applicationManager.mainStageFocusedApplication
274 && !shell.applicationManager.sideStageFocusedApplication
275 && shell.applicationManager.mainStageApplications.count == 0
276 && shell.applicationManager.sideStageApplications.count == 0) {
277 stages.hide();
278 }
279 }
281 // show the stages when an application gets the focus
282 Connections {
283 target: shell.applicationManager
284 onMainStageFocusedApplicationChanged: {
285 if (shell.applicationManager.mainStageFocusedApplication) {
286 mainStage.show();
287 stages.show();
288 }
289 }
290 onSideStageFocusedApplicationChanged: {
291 if (shell.applicationManager.sideStageFocusedApplication) {
292 sideStage.show();
293 stages.show();
294 }
295 }
296 ignoreUnknownSignals: true
297 }
299 Stage {
300 id: mainStage
302 anchors.fill: parent
303 fullyShown: stages.fullyShown
304 fullyHidden: stages.fullyHidden
305 shouldUseScreenshots: !fullyShown
306 rightEdgeEnabled: !sideStage.enabled
308 applicationManager: shell.applicationManager
309 rightEdgeDraggingAreaWidth: shell.edgeSize
310 normalApplicationY: shell.panelHeight
312 shown: true
313 function show() {
314 stages.show();
315 }
316 function hide() {
317 }
319 // FIXME: workaround the fact that focusing a main stage application
320 // raises its surface on top of all other surfaces including the ones
321 // that belong to side stage applications.
322 onFocusedApplicationChanged: {
323 if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
324 shell.applicationManager.focusApplication(sideStage.focusedApplication);
325 }
326 }
327 }
329 SideStage {
330 id: sideStage
332 applicationManager: shell.applicationManager
333 rightEdgeDraggingAreaWidth: shell.edgeSize
334 normalApplicationY: shell.panelHeight
336 onShownChanged: {
337 if (!shown && mainStage.applications.count == 0) {
338 stages.hide();
339 }
340 }
341 // FIXME: when hiding the side stage, refocus the main stage
342 // application so that it goes in front of the side stage
343 // application and hides it
344 onFullyShownChanged: {
345 if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
346 shell.applicationManager.focusApplication(mainStage.focusedApplication);
347 }
348 }
350 enabled: shell.width >= units.gu(60)
351 visible: enabled
352 fullyShown: stages.fullyShown && shown
353 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
354 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
356 available: !greeter.shown && !lockscreen.shown && enabled
357 hides: [launcher, panel.indicators]
358 shown: false
359 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
360 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
362 width: units.gu(40)
363 height: stages.height
364 handleExpanded: sideStageRevealer.pressed
365 }
367 Revealer {
368 id: sideStageRevealer
370 enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
371 && sideStage.available
372 direction: Qt.RightToLeft
373 openedValue: parent.width - sideStage.width
374 hintDisplacement: units.gu(3)
375 /* The size of the sidestage handle needs to be bigger than the
376 typical size used for edge detection otherwise it is really
377 hard to grab.
378 */
379 handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
380 closedValue: parent.width + sideStage.handleSizeCollapsed
381 target: sideStage
382 x: parent.width - width
383 width: sideStage.width + handleSize * 0.7
384 height: sideStage.height
385 orientation: Qt.Horizontal
386 }
388 // Defines the rectangle occupied by an application on the main or side stage.
389 // Used only to inform the ApplicationManager. Can be removed when the proper
390 // architecture is in place (unity8 as mir compositor).
391 Item {
392 id: mainStageAppRect
393 x: mainStage.x
394 y: mainStage.y + mainStage.normalApplicationY
395 width: mainStage.width
396 height: mainStage.height
397 visible: false; enabled: false
398 }
399 Item {
400 id: sideStageAppRect
401 x: sideStageRevealer.openedValue
402 y: sideStage.y + sideStage.normalApplicationY
403 width: sideStage.width
404 height: sideStage.height
405 visible: false; enabled: false
406 }
408 DragHandle {
409 id: stagesDragHandle
411 anchors.top: parent.top
412 anchors.bottom: parent.bottom
413 anchors.right: parent.left
415 width: shell.edgeSize
416 direction: Direction.Leftwards
417 enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled
418 property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
420 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
421 // Make autocompletion impossible when !haveApps
422 edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
423 }
424 }
425 }
427 Lockscreen {
428 id: lockscreen
429 objectName: "lockscreen"
431 readonly property int backgroundTopMargin: -panel.panelHeight
433 hides: [launcher, panel.indicators, hud]
434 shown: false
435 enabled: true
436 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
437 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
438 y: panel.panelHeight
439 x: required ? 0 : - width
440 width: parent.width
441 height: parent.height - panel.panelHeight
442 background: shell.background
443 pinLength: 4
445 onEntered: LightDM.Greeter.respond(passphrase);
446 onCancel: greeter.show()
448 Component.onCompleted: {
449 if (LightDM.Users.count == 1) {
450 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
451 greeter.selected(0)
452 }
453 }
454 }
456 Connections {
457 target: LightDM.Greeter
459 onShowPrompt: {
460 if (LightDM.Users.count == 1) {
461 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
462 if (text == "PIN") {
463 lockscreen.alphaNumeric = false
464 } else {
465 lockscreen.alphaNumeric = true
466 }
467 lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
468 lockscreen.show();
469 }
470 }
472 onAuthenticationComplete: {
473 if (LightDM.Greeter.promptless) {
474 return;
475 }
476 if (LightDM.Greeter.authenticated) {
477 lockscreen.hide();
478 } else {
479 lockscreen.clear(true);
480 }
481 }
482 }
484 Greeter {
485 id: greeter
486 objectName: "greeter"
488 available: true
489 hides: [launcher, panel.indicators, hud]
490 shown: true
492 defaultBackground: shell.background
494 y: panel.panelHeight
495 width: parent.width
496 height: parent.height - panel.panelHeight
498 dragHandleWidth: shell.edgeSize
500 property var previousMainApp: null
501 property var previousSideApp: null
503 function removeApplicationFocus() {
504 greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
505 if (sideStage.fullyShown) { // if side stage hidden, don't focus it on restore
506 greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
507 }
508 applicationManager.unfocusCurrentApplication();
509 }
511 function restoreApplicationFocus() {
512 if (greeter.previousMainApp) {
513 applicationManager.focusApplication(greeter.previousMainApp);
514 greeter.previousMainApp = null;
515 }
516 if (greeter.previousSideApp) {
517 applicationManager.focusApplication(greeter.previousSideApp);
518 greeter.previousSideApp = null;
519 }
520 }
522 onShownChanged: {
523 if (shown) {
524 lockscreen.reset();
525 // If there is only one user, we start authenticating with that one here.
526 // If there are more users, the Greeter will handle that
527 if (LightDM.Users.count == 1) {
528 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
529 greeter.selected(0);
530 }
531 greeter.forceActiveFocus();
532 removeApplicationFocus();
533 } else {
534 restoreApplicationFocus();
535 }
536 }
538 onUnlocked: greeter.hide()
539 onSelected: {
540 // Update launcher items for new user
541 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
542 AccountsService.user = user;
543 LauncherModel.setUser(user);
544 }
546 onLeftTeaserPressedChanged: {
547 if (leftTeaserPressed) {
548 launcher.tease();
549 }
550 }
552 Connections {
553 target: applicationManager
554 ignoreUnknownSignals: true
555 // If any app is focused when greeter is open, it's due to a user action
556 // like a snap decision (say, an incoming call).
557 // TODO: these should be protected to only unlock for certain applications / certain usecases
558 // potentially only in connection with a notification.
559 onMainStageFocusedApplicationChanged: {
560 if (greeter.shown && applicationManager.mainStageFocusedApplication) {
561 greeter.previousMainApp = null // make way for new focused app
562 greeter.previousSideApp = null
563 greeter.hide()
564 }
565 }
566 onSideStageFocusedApplicationChanged: {
567 if (greeter.shown && applicationManager.sideStageFocusedApplication) {
568 greeter.previousMainApp = null // make way for new focused app
569 greeter.previousSideApp = null
570 greeter.hide()
571 }
572 }
573 }
574 }
576 InputFilterArea {
577 width: {
578 if (applicationManager.sideStageFocusedApplication)
579 return parent.width - sideStage.width;
580 else
581 return parent.width;
582 }
583 height: parent.height
584 blockInput: !applicationManager.mainStageFocusedApplication || greeter.shown || lockscreen.shown || launcher.shown
585 || panel.indicators.shown || hud.shown
586 }
588 Connections {
589 id: powerConnection
590 target: Powerd
592 onDisplayPowerStateChange: {
593 // We ignore any display-off signals when the proximity sensor
594 // is active. This usually indicates something like a phone call.
595 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
596 greeter.showNow();
597 }
599 // No reason to chew demo CPU when user isn't watching
600 if (status == Powerd.Off) {
601 edgeDemo.paused = true;
602 } else if (status == Powerd.On) {
603 edgeDemo.paused = false;
604 }
605 }
606 }
608 function showHome() {
609 var animate = !greeter.shown && !stages.shown
610 greeter.hide()
611 dash.setCurrentScope("clickscope", animate, false)
612 stages.hide()
613 }
615 function hideIndicatorMenu(delay) {
616 panel.hideIndicatorMenu(delay);
617 }
619 Item {
620 id: overlay
622 anchors.fill: parent
624 Panel {
625 id: panel
626 anchors.fill: parent //because this draws indicator menus
627 indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
628 indicators {
629 hides: [launcher]
630 available: edgeDemo.panelEnabled
631 contentEnabled: edgeDemo.panelContentEnabled
632 }
633 fullscreenMode: shell.fullscreenMode
634 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown
636 InputFilterArea {
637 anchors {
638 top: parent.top
639 left: parent.left
640 right: parent.right
641 }
642 height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
643 blockInput: true
644 }
645 }
647 Hud {
648 id: hud
650 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
651 height: parent.height
653 available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && edgeDemo.dashEnabled
654 shown: false
655 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
656 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
658 Connections {
659 target: shell.applicationManager
660 onMainStageFocusedApplicationChanged: hud.hide()
661 onSideStageFocusedApplicationChanged: hud.hide()
662 }
663 }
665 Revealer {
666 id: hudRevealer
668 enabled: hud.shown
669 width: hud.width
670 anchors.left: hud.left
671 height: parent.height
672 target: hud.revealerTarget
673 closedValue: height
674 openedValue: 0
675 direction: Qt.RightToLeft
676 orientation: Qt.Vertical
677 handleSize: hud.handleHeight
678 onCloseClicked: target.hide()
679 }
681 Bottombar {
682 id: bottombar
683 theHud: hud
684 anchors.fill: parent
685 enabled: hud.available
686 applicationIsOnForeground: applicationFocused
687 }
689 InputFilterArea {
690 blockInput: launcher.shown
691 anchors {
692 top: parent.top
693 bottom: parent.bottom
694 left: parent.left
695 }
696 width: launcher.width
697 }
699 Launcher {
700 id: launcher
702 readonly property bool dashSwipe: progress > 0
704 anchors.top: parent.top
705 anchors.bottom: parent.bottom
706 width: parent.width
707 dragAreaWidth: shell.edgeSize
708 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
710 onShowDashHome: {
711 if (edgeDemo.running)
712 return;
714 showHome()
715 }
716 onDash: {
717 if (stages.shown) {
718 stages.hide();
719 launcher.hide();
720 }
721 }
722 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
723 onLauncherApplicationSelected:{
724 if (edgeDemo.running)
725 return;
727 greeter.hide()
728 shell.activateApplication(appId)
729 }
730 onShownChanged: {
731 if (shown) {
732 panel.indicators.hide()
733 hud.hide()
734 bottombar.hide()
735 }
736 }
737 }
739 Notifications {
740 id: notifications
742 model: NotificationBackend.Model
743 margin: units.gu(1)
745 anchors {
746 top: parent.top
747 right: parent.right
748 bottom: parent.bottom
749 topMargin: panel.panelHeight
750 }
751 states: [
752 State {
753 name: "narrow"
754 when: overlay.width <= units.gu(60)
755 AnchorChanges { target: notifications; anchors.left: parent.left }
756 },
757 State {
758 name: "wide"
759 when: overlay.width > units.gu(60)
760 AnchorChanges { target: notifications; anchors.left: undefined }
761 PropertyChanges { target: notifications; width: units.gu(38) }
762 }
763 ]
765 InputFilterArea {
766 anchors { left: parent.left; right: parent.right }
767 height: parent.contentHeight
768 blockInput: height > 0
769 }
770 }
771 }
773 focus: true
774 onFocusChanged: if (!focus) forceActiveFocus();
776 InputFilterArea {
777 anchors {
778 top: parent.top
779 bottom: parent.bottom
780 left: parent.left
781 }
782 width: shell.edgeSize
783 blockInput: true
784 }
786 InputFilterArea {
787 anchors {
788 top: parent.top
789 bottom: parent.bottom
790 right: parent.right
791 }
792 width: shell.edgeSize
793 blockInput: true
794 }
796 Binding {
797 target: i18n
798 property: "domain"
799 value: "unity8"
800 }
802 Label {
803 anchors.centerIn: parent
804 visible: applicationManager.fake
805 text: "EARLY ALPHA\nNOT READY FOR USE"
806 color: "lightgrey"
807 opacity: 0.2
808 font.weight: Font.Black
809 horizontalAlignment: Text.AlignHCenter
810 verticalAlignment: Text.AlignVCenter
811 fontSizeMode: Text.Fit
812 rotation: -45
813 scale: Math.min(parent.width, parent.height) / width
814 }
816 EdgeDemo {
817 id: edgeDemo
818 greeter: greeter
819 launcher: launcher
820 dash: dash
821 indicators: panel.indicators
822 underlay: underlay
823 }
825 Connections {
826 target: SessionBroadcast
827 onShowHome: showHome()
828 }