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