on 7.84+14.04.20140228-0ubuntu1 help sign in
unity8/qml/Shell.qml
809 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 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();
80 }
82 readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
83 || !!applicationManager.sideStageFocusedApplication
84 // Used for autopilot testing.
85 readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
87 readonly property bool fullscreenMode: {
88 if (greeter.shown || lockscreen.shown) {
89 return false;
90 } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
91 return mainStage.switchingFromFullscreenToFullscreen;
92 } else if (applicationManager.mainStageFocusedApplication) {
93 return applicationManager.mainStageFocusedApplication.fullscreen;
94 } else {
95 return false;
96 }
97 }
99 function activateApplication(appId, argument) {
100 if (applicationManager) {
101 // For newly started applications, as it takes them time to draw their first frame
102 // we add a delay before we hide the animation screenshots to compensate.
103 var addDelay = !applicationManager.getApplicationFromDesktopFile(appId);
105 var application;
106 application = applicationManager.activateApplication(appId, argument);
107 if (application == null) {
108 return;
109 }
110 if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
111 mainStage.activateApplication(appId, addDelay);
112 } else {
113 sideStage.activateApplication(appId, addDelay);
114 }
115 stages.show();
116 }
117 }
119 GSettings {
120 id: backgroundSettings
121 schema.id: "org.gnome.desktop.background"
122 }
123 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
124 onGSettingsPictureChanged: {
125 shell.background = gSettingsPicture
126 }
128 // This is a dummy image that is needed to determine if the picture url
129 // in backgroundSettings points to a valid picture file.
130 // We can't do this with the real background image because setting a
131 // new source in onStatusChanged triggers a binding loop detection
132 // inside Image, which causes it not to render even though a valid source
133 // would be set. We don't mind about this image staying black and just
134 // use it for verification to populate the source for the real
135 // background image.
136 Image {
137 source: shell.background
138 height: 0
139 width: 0
140 sourceSize.height: 0
141 sourceSize.width: 0
142 onStatusChanged: {
143 if (status == Image.Error && source != shell.defaultBackground) {
144 shell.background = defaultBackground
145 }
146 }
147 }
149 VolumeControl {
150 id: volumeControl
151 }
153 Keys.onVolumeUpPressed: volumeControl.volumeUp()
154 Keys.onVolumeDownPressed: volumeControl.volumeDown()
156 Item {
157 id: underlay
158 objectName: "underlay"
159 anchors.fill: parent
161 // Whether the underlay is fully covered by opaque UI elements.
162 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
164 readonly property bool applicationRunning: ((mainStage.applications && mainStage.applications.count > 0)
165 || (sideStage.applications && sideStage.applications.count > 0))
167 // Whether the user should see the topmost application surface (if there's one at all).
168 readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.fullyHidden
169 && !mainStage.usingScreenshots // but want sideStage animating over app surface
173 // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
174 // through the translucent parts of the shell surface.
175 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
177 CrossFadeImage {
178 id: backgroundImage
179 objectName: "backgroundImage"
181 anchors.fill: parent
182 source: shell.background
183 fillMode: Image.PreserveAspectCrop
184 }
186 Rectangle {
187 anchors.fill: parent
188 color: "black"
189 opacity: dash.disappearingAnimationProgress
190 }
192 Dash {
193 id: dash
194 objectName: "dash"
196 available: !greeter.shown && !lockscreen.shown
197 hides: [stages, launcher, panel.indicators]
198 shown: disappearingAnimationProgress !== 1.0
199 enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
200 // FIXME: unfocus all applications when going back to the dash
201 onEnabledChanged: {
202 if (enabled) {
203 shell.applicationManager.unfocusCurrentApplication()
204 }
205 }
207 anchors {
208 fill: parent
209 topMargin: panel.panelHeight
210 }
212 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
213 opacity: 1.0 - disappearingAnimationProgress
214 property real disappearingAnimationProgress: {
215 if (greeter.shown) {
216 return greeter.showProgress;
217 } else {
218 return stagesOuterContainer.showProgress;
219 }
220 }
222 // FIXME: only necessary because stagesOuterContainer.showProgress and
223 // greeterRevealer.animatedProgress are not animated
224 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
225 }
226 }
228 Item {
229 id: stagesOuterContainer
231 width: parent.width
232 height: parent.height
233 x: launcher.progress
234 Behavior on x {SmoothedAnimation{velocity: 600}}
236 property real showProgress:
237 MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
239 Showable {
240 id: stages
241 objectName: "stages"
243 x: width
245 property bool fullyShown: shown && x == 0 && parent.x == 0
246 property bool fullyHidden: !shown && x == width
247 available: !greeter.shown
248 hides: [panel.indicators]
249 shown: false
250 opacity: 1.0
251 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
252 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
254 width: parent.width
255 height: parent.height
257 // close the stages when no focused application remains
258 Connections {
259 target: shell.applicationManager
260 onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
261 onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
262 ignoreUnknownSignals: true
263 }
265 function closeIfNoApplications() {
266 if (!shell.applicationManager.mainStageFocusedApplication
267 && !shell.applicationManager.sideStageFocusedApplication
268 && shell.applicationManager.mainStageApplications.count == 0
269 && shell.applicationManager.sideStageApplications.count == 0) {
270 stages.hide();
271 }
272 }
274 // show the stages when an application gets the focus
275 Connections {
276 target: shell.applicationManager
277 onMainStageFocusedApplicationChanged: {
278 if (shell.applicationManager.mainStageFocusedApplication) {
279 mainStage.show();
280 stages.show();
281 }
282 }
283 onSideStageFocusedApplicationChanged: {
284 if (shell.applicationManager.sideStageFocusedApplication) {
285 sideStage.show();
286 stages.show();
287 }
288 }
289 ignoreUnknownSignals: true
290 }
292 Stage {
293 id: mainStage
295 anchors.fill: parent
296 fullyShown: stages.fullyShown
297 fullyHidden: stages.fullyHidden
298 shouldUseScreenshots: !fullyShown
299 rightEdgeEnabled: !sideStage.enabled
301 applicationManager: shell.applicationManager
302 rightEdgeDraggingAreaWidth: shell.edgeSize
303 normalApplicationY: shell.panelHeight
305 shown: true
306 function show() {
307 stages.show();
308 }
309 function hide() {
310 }
312 // FIXME: workaround the fact that focusing a main stage application
313 // raises its surface on top of all other surfaces including the ones
314 // that belong to side stage applications.
315 onFocusedApplicationChanged: {
316 if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
317 shell.applicationManager.focusApplication(sideStage.focusedApplication);
318 }
319 }
320 }
322 SideStage {
323 id: sideStage
325 applicationManager: shell.applicationManager
326 rightEdgeDraggingAreaWidth: shell.edgeSize
327 normalApplicationY: shell.panelHeight
329 onShownChanged: {
330 if (!shown && mainStage.applications.count == 0) {
331 stages.hide();
332 }
333 }
334 // FIXME: when hiding the side stage, refocus the main stage
335 // application so that it goes in front of the side stage
336 // application and hides it
337 onFullyShownChanged: {
338 if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
339 shell.applicationManager.focusApplication(mainStage.focusedApplication);
340 }
341 }
343 enabled: shell.width >= units.gu(100)
344 visible: enabled
345 fullyShown: stages.fullyShown && shown
346 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
347 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
349 available: !greeter.shown && !lockscreen.shown && enabled
350 hides: [launcher, panel.indicators]
351 shown: false
352 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
353 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
355 width: units.gu(40)
356 height: stages.height
357 handleExpanded: sideStageRevealer.pressed
358 }
360 Revealer {
361 id: sideStageRevealer
363 enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
364 && sideStage.available
365 direction: Qt.RightToLeft
366 openedValue: parent.width - sideStage.width
367 hintDisplacement: units.gu(3)
368 /* The size of the sidestage handle needs to be bigger than the
369 typical size used for edge detection otherwise it is really
370 hard to grab.
371 */
372 handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
373 closedValue: parent.width + sideStage.handleSizeCollapsed
374 target: sideStage
375 x: parent.width - width
376 width: sideStage.width + handleSize * 0.7
377 height: sideStage.height
378 orientation: Qt.Horizontal
379 }
381 DragHandle {
382 id: stagesDragHandle
384 anchors.top: parent.top
385 anchors.bottom: parent.bottom
386 anchors.right: parent.left
388 width: shell.edgeSize
389 direction: Direction.Leftwards
390 enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled
391 property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
393 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
394 // Make autocompletion impossible when !haveApps
395 edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
396 }
397 }
398 }
400 Lockscreen {
401 id: lockscreen
402 objectName: "lockscreen"
404 readonly property int backgroundTopMargin: -panel.panelHeight
406 hides: [launcher, panel.indicators, hud]
407 shown: false
408 enabled: true
409 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
410 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
411 y: panel.panelHeight
412 x: required ? 0 : - width
413 width: parent.width
414 height: parent.height - panel.panelHeight
415 background: shell.background
416 pinLength: 4
418 onEntered: LightDM.Greeter.respond(passphrase);
419 onCancel: greeter.show()
421 Component.onCompleted: {
422 if (LightDM.Users.count == 1) {
423 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
424 greeter.selected(0)
425 }
426 }
427 }
429 Connections {
430 target: LightDM.Greeter
432 onShowPrompt: {
433 if (LightDM.Users.count == 1) {
434 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
435 if (text == "PIN") {
436 lockscreen.alphaNumeric = false
437 } else {
438 lockscreen.alphaNumeric = true
439 }
440 lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
441 lockscreen.show();
442 }
443 }
445 onAuthenticationComplete: {
446 if (LightDM.Greeter.promptless) {
447 return;
448 }
449 if (LightDM.Greeter.authenticated) {
450 lockscreen.hide();
451 } else {
452 lockscreen.clear(true);
453 }
454 }
455 }
457 Greeter {
458 id: greeter
459 objectName: "greeter"
461 available: true
462 hides: [launcher, panel.indicators, hud]
463 shown: true
465 defaultBackground: shell.background
467 y: panel.panelHeight
468 width: parent.width
469 height: parent.height - panel.panelHeight
471 dragHandleWidth: shell.edgeSize
473 property var previousMainApp: null
474 property var previousSideApp: null
476 function removeApplicationFocus() {
477 greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
478 greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
479 applicationManager.unfocusCurrentApplication();
480 }
482 function restoreApplicationFocus() {
483 if (greeter.previousMainApp) {
484 applicationManager.focusApplication(greeter.previousMainApp);
485 greeter.previousMainApp = null;
486 }
487 if (greeter.previousSideApp) {
488 applicationManager.focusApplication(greeter.previousSideApp);
489 greeter.previousSideApp = null;
490 }
491 }
493 onShownChanged: {
494 if (shown) {
495 lockscreen.reset();
496 // If there is only one user, we start authenticating with that one here.
497 // If there are more users, the Greeter will handle that
498 if (LightDM.Users.count == 1) {
499 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
500 greeter.selected(0);
501 }
502 greeter.forceActiveFocus();
503 removeApplicationFocus();
504 } else {
505 restoreApplicationFocus();
506 }
507 }
509 onUnlocked: greeter.hide()
510 onSelected: {
511 // Update launcher items for new user
512 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
513 AccountsService.user = user;
514 LauncherModel.setUser(user);
515 }
517 onLeftTeaserPressedChanged: {
518 if (leftTeaserPressed) {
519 launcher.tease();
520 }
521 }
523 Connections {
524 target: applicationManager
525 ignoreUnknownSignals: true
526 // If any app is focused when greeter is open, it's due to a user action
527 // like a snap decision (say, an incoming call).
528 // TODO: these should be protected to only unlock for certain applications / certain usecases
529 // potentially only in connection with a notification.
530 onMainStageFocusedApplicationChanged: {
531 if (greeter.shown && applicationManager.mainStageFocusedApplication) {
532 greeter.previousMainApp = null // make way for new focused app
533 greeter.previousSideApp = null
534 greeter.hide()
535 }
536 }
537 onSideStageFocusedApplicationChanged: {
538 if (greeter.shown && applicationManager.sideStageFocusedApplication) {
539 greeter.previousMainApp = null // make way for new focused app
540 greeter.previousSideApp = null
541 greeter.hide()
542 }
543 }
544 }
545 }
547 InputFilterArea {
548 anchors.fill: parent
549 blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
550 || panel.indicators.shown || hud.shown
551 }
553 Connections {
554 id: powerConnection
555 target: Powerd
557 onDisplayPowerStateChange: {
558 // We ignore any display-off signals when the proximity sensor
559 // is active. This usually indicates something like a phone call.
560 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
561 greeter.showNow();
562 }
564 // No reason to chew demo CPU when user isn't watching
565 if (status == Powerd.Off) {
566 edgeDemo.paused = true;
567 } else if (status == Powerd.On) {
568 edgeDemo.paused = false;
569 }
570 }
571 }
573 function showHome() {
574 var animate = !greeter.shown && !stages.shown
575 greeter.hide()
576 dash.setCurrentScope("home.scope", animate, false)
577 stages.hide()
578 }
580 function hideIndicatorMenu(delay) {
581 panel.hideIndicatorMenu(delay);
582 }
584 Item {
585 id: overlay
587 anchors.fill: parent
589 Panel {
590 id: panel
591 anchors.fill: parent //because this draws indicator menus
592 indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
593 indicators {
594 hides: [launcher]
595 available: edgeDemo.panelEnabled
596 contentEnabled: edgeDemo.panelContentEnabled
597 }
598 fullscreenMode: shell.fullscreenMode
599 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown
601 InputFilterArea {
602 anchors {
603 top: parent.top
604 left: parent.left
605 right: parent.right
606 }
607 height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
608 blockInput: true
609 }
610 }
612 Hud {
613 id: hud
615 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
616 height: parent.height
618 available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && edgeDemo.dashEnabled
619 shown: false
620 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
621 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
623 Connections {
624 target: shell.applicationManager
625 onMainStageFocusedApplicationChanged: hud.hide()
626 onSideStageFocusedApplicationChanged: hud.hide()
627 }
628 }
630 Revealer {
631 id: hudRevealer
633 enabled: hud.shown
634 width: hud.width
635 anchors.left: hud.left
636 height: parent.height
637 target: hud.revealerTarget
638 closedValue: height
639 openedValue: 0
640 direction: Qt.RightToLeft
641 orientation: Qt.Vertical
642 handleSize: hud.handleHeight
643 onCloseClicked: target.hide()
644 }
646 Bottombar {
647 id: bottombar
648 theHud: hud
649 anchors.fill: parent
650 enabled: hud.available
651 applicationIsOnForeground: applicationFocused
652 }
654 InputFilterArea {
655 blockInput: launcher.shown
656 anchors {
657 top: parent.top
658 bottom: parent.bottom
659 left: parent.left
660 }
661 width: launcher.width
662 }
664 Launcher {
665 id: launcher
667 readonly property bool dashSwipe: progress > 0
669 anchors.top: parent.top
670 anchors.bottom: parent.bottom
671 width: parent.width
672 dragAreaWidth: shell.edgeSize
673 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
675 onShowDashHome: {
676 if (edgeDemo.running)
677 return;
679 showHome()
680 }
681 onDash: {
682 if (stages.shown) {
683 stages.hide();
684 launcher.hide();
685 }
686 }
687 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("applications.scope", false, true)
688 onLauncherApplicationSelected:{
689 if (edgeDemo.running)
690 return;
692 greeter.hide()
693 shell.activateApplication(appId)
694 }
695 onShownChanged: {
696 if (shown) {
697 panel.indicators.hide()
698 hud.hide()
699 bottombar.hide()
700 }
701 }
702 }
704 Notifications {
705 id: notifications
707 model: NotificationBackend.Model
708 margin: units.gu(1)
710 anchors {
711 top: parent.top
712 right: parent.right
713 bottom: parent.bottom
714 topMargin: panel.panelHeight
715 }
716 states: [
717 State {
718 name: "narrow"
719 when: overlay.width <= units.gu(60)
720 AnchorChanges { target: notifications; anchors.left: parent.left }
721 },
722 State {
723 name: "wide"
724 when: overlay.width > units.gu(60)
725 AnchorChanges { target: notifications; anchors.left: undefined }
726 PropertyChanges { target: notifications; width: units.gu(38) }
727 }
728 ]
730 InputFilterArea {
731 anchors { left: parent.left; right: parent.right }
732 height: parent.contentHeight
733 blockInput: height > 0
734 }
735 }
736 }
738 focus: true
739 onFocusChanged: if (!focus) forceActiveFocus();
741 InputFilterArea {
742 anchors {
743 top: parent.top
744 bottom: parent.bottom
745 left: parent.left
746 }
747 width: shell.edgeSize
748 blockInput: true
749 }
751 InputFilterArea {
752 anchors {
753 top: parent.top
754 bottom: parent.bottom
755 right: parent.right
756 }
757 width: shell.edgeSize
758 blockInput: true
759 }
761 Binding {
762 target: i18n
763 property: "domain"
764 value: "unity8"
765 }
767 OSKController {
768 anchors.topMargin: panel.panelHeight
769 anchors.fill: parent // as needs to know the geometry of the shell
770 }
772 //FIXME: This should be handled in the input stack, keyboard shouldnt propagate
773 MouseArea {
774 anchors.bottom: parent.bottom
775 anchors.left: parent.left
776 anchors.right: parent.right
777 height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0
779 enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
780 }
782 Label {
783 anchors.centerIn: parent
784 visible: applicationManager.fake
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 greeter: greeter
799 launcher: launcher
800 dash: dash
801 indicators: panel.indicators
802 underlay: underlay
803 }
805 Connections {
806 target: SessionBroadcast
807 onShowHome: showHome()
808 }