on 0fea3d1 help sign in
unity8/qml/Shell.qml
798 lines 28 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
40 objectName: "shell"
42 // this is only here to select the width / height of the window if not running fullscreen
43 property bool tablet: false
44 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
45 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
47 property real edgeSize: units.gu(2)
48 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
49 property url background
50 readonly property real panelHeight: panel.panelHeight
52 property bool dashShown: dash.shown
53 property bool stageScreenshotsReady: {
54 if (sideStage.shown) {
55 if (mainStage.applications.count > 0) {
56 return mainStage.usingScreenshots && sideStage.usingScreenshots;
57 } else {
58 return sideStage.usingScreenshots;
59 }
60 } else {
61 return mainStage.usingScreenshots;
62 }
63 }
65 property var applicationManager: ApplicationManagerWrapper {}
67 Binding {
68 target: LauncherModel
69 property: "applicationManager"
70 value: ApplicationManager
71 }
73 Component.onCompleted: {
74 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
76 applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
78 // FIXME: if application focused before shell starts, shell draws on top of it only.
79 // We should detect already running applications on shell start and bring them to the front.
80 applicationManager.unfocusCurrentApplication();
82 applicationManager.setMainStageAppRect(mainStageAppRect);
83 applicationManager.setSideStageAppRect(sideStageAppRect);
84 }
86 readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
87 || !!applicationManager.sideStageFocusedApplication
88 // Used for autopilot testing.
89 readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
91 readonly property bool fullscreenMode: {
92 if (greeter.shown || lockscreen.shown) {
93 return false;
94 } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
95 return mainStage.switchingFromFullscreenToFullscreen;
96 } else if (applicationManager.mainStageFocusedApplication) {
97 return applicationManager.mainStageFocusedApplication.fullscreen;
98 } else {
99 return false;
100 }
101 }
103 function activateApplication(appId, argument) {
104 if (applicationManager) {
105 // For newly started applications, as it takes them time to draw their first frame
106 // we add a delay before we hide the animation screenshots to compensate.
107 var addDelay = !applicationManager.getApplicationFromDesktopFile(appId);
109 var application;
110 application = applicationManager.activateApplication(appId, argument);
111 if (application == null) {
112 return;
113 }
114 if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
115 mainStage.activateApplication(appId, addDelay);
116 } else {
117 sideStage.activateApplication(appId, addDelay);
118 }
119 stages.show();
120 }
121 }
123 GSettings {
124 id: backgroundSettings
125 schema.id: "org.gnome.desktop.background"
126 }
127 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
128 onGSettingsPictureChanged: {
129 shell.background = gSettingsPicture
130 }
132 VolumeControl {
133 id: volumeControl
134 }
136 Keys.onVolumeUpPressed: volumeControl.volumeUp()
137 Keys.onVolumeDownPressed: volumeControl.volumeDown()
139 Item {
140 id: underlay
141 objectName: "underlay"
142 anchors.fill: parent
144 // Whether the underlay is fully covered by opaque UI elements.
145 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
147 readonly property bool applicationRunning: ((mainStage.applications && mainStage.applications.count > 0)
148 || (sideStage.applications && sideStage.applications.count > 0))
150 // Whether the user should see the topmost application surface (if there's one at all).
151 readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.fullyHidden
152 && !mainStage.usingScreenshots // but want sideStage animating over app surface
156 // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
157 // through the translucent parts of the shell surface.
158 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
160 Rectangle {
161 anchors.fill: parent
162 color: "black"
163 opacity: dash.disappearingAnimationProgress
164 }
166 Image {
167 anchors.fill: dash
168 source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
169 fillMode: Image.PreserveAspectCrop
170 horizontalAlignment: Image.AlignRight
171 verticalAlignment: Image.AlignTop
172 }
174 Dash {
175 id: dash
176 objectName: "dash"
178 available: !greeter.shown && !lockscreen.shown
179 hides: [stages, launcher, panel.indicators]
180 shown: disappearingAnimationProgress !== 1.0
181 enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
182 // FIXME: unfocus all applications when going back to the dash
183 onEnabledChanged: {
184 if (enabled) {
185 shell.applicationManager.unfocusCurrentApplication()
186 }
187 }
189 anchors {
190 fill: parent
191 topMargin: panel.panelHeight
192 }
194 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
195 opacity: 1.0 - disappearingAnimationProgress
196 property real disappearingAnimationProgress: {
197 if (greeter.shown) {
198 return greeter.showProgress;
199 } else {
200 return stagesOuterContainer.showProgress;
201 }
202 }
204 // FIXME: only necessary because stagesOuterContainer.showProgress and
205 // greeterRevealer.animatedProgress are not animated
206 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
207 }
208 }
210 Item {
211 id: stagesOuterContainer
213 width: parent.width
214 height: parent.height
215 x: launcher.progress
216 Behavior on x {SmoothedAnimation{velocity: 600}}
218 property real showProgress:
219 MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
221 Showable {
222 id: stages
223 objectName: "stages"
225 x: width
227 property bool fullyShown: shown && x == 0 && parent.x == 0
228 property bool fullyHidden: !shown && x == width
229 available: !greeter.shown
230 hides: [panel.indicators]
231 shown: false
232 opacity: 1.0
233 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
234 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
236 width: parent.width
237 height: parent.height
239 // close the stages when no focused application remains
240 Connections {
241 target: shell.applicationManager
242 onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
243 onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
244 ignoreUnknownSignals: true
245 }
247 function closeIfNoApplications() {
248 if (!shell.applicationManager.mainStageFocusedApplication
249 && !shell.applicationManager.sideStageFocusedApplication
250 && shell.applicationManager.mainStageApplications.count == 0
251 && shell.applicationManager.sideStageApplications.count == 0) {
252 stages.hide();
253 }
254 }
256 // show the stages when an application gets the focus
257 Connections {
258 target: shell.applicationManager
259 onMainStageFocusedApplicationChanged: {
260 if (shell.applicationManager.mainStageFocusedApplication) {
261 mainStage.show();
262 stages.show();
263 }
264 }
265 onSideStageFocusedApplicationChanged: {
266 if (shell.applicationManager.sideStageFocusedApplication) {
267 sideStage.show();
268 stages.show();
269 }
270 }
271 ignoreUnknownSignals: true
272 }
274 Stage {
275 id: mainStage
277 anchors.fill: parent
278 fullyShown: stages.fullyShown
279 fullyHidden: stages.fullyHidden
280 shouldUseScreenshots: !fullyShown
281 rightEdgeEnabled: !sideStage.enabled
283 applicationManager: shell.applicationManager
284 rightEdgeDraggingAreaWidth: shell.edgeSize
285 normalApplicationY: shell.panelHeight
287 shown: true
288 function show() {
289 stages.show();
290 }
291 function hide() {
292 }
294 // FIXME: workaround the fact that focusing a main stage application
295 // raises its surface on top of all other surfaces including the ones
296 // that belong to side stage applications.
297 onFocusedApplicationChanged: {
298 if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
299 shell.applicationManager.focusApplication(sideStage.focusedApplication);
300 }
301 }
302 }
304 SideStage {
305 id: sideStage
307 applicationManager: shell.applicationManager
308 rightEdgeDraggingAreaWidth: shell.edgeSize
309 normalApplicationY: shell.panelHeight
311 onShownChanged: {
312 if (!shown && mainStage.applications.count == 0) {
313 stages.hide();
314 }
315 }
316 // FIXME: when hiding the side stage, refocus the main stage
317 // application so that it goes in front of the side stage
318 // application and hides it
319 onFullyShownChanged: {
320 if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
321 shell.applicationManager.focusApplication(mainStage.focusedApplication);
322 }
323 }
325 enabled: shell.width >= units.gu(60)
326 visible: enabled
327 fullyShown: stages.fullyShown && shown
328 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
329 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
331 available: !greeter.shown && !lockscreen.shown && enabled
332 hides: [launcher, panel.indicators]
333 shown: false
334 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
335 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
337 width: units.gu(40)
338 height: stages.height
339 handleExpanded: sideStageRevealer.pressed
340 }
342 Revealer {
343 id: sideStageRevealer
345 enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
346 && sideStage.available
347 direction: Qt.RightToLeft
348 openedValue: parent.width - sideStage.width
349 hintDisplacement: units.gu(3)
350 /* The size of the sidestage handle needs to be bigger than the
351 typical size used for edge detection otherwise it is really
352 hard to grab.
353 */
354 handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
355 closedValue: parent.width + sideStage.handleSizeCollapsed
356 target: sideStage
357 x: parent.width - width
358 width: sideStage.width + handleSize * 0.7
359 height: sideStage.height
360 orientation: Qt.Horizontal
361 }
363 // Defines the rectangle occupied by an application on the main or side stage.
364 // Used only to inform the ApplicationManager. Can be removed when the proper
365 // architecture is in place (unity8 as mir compositor).
366 Item {
367 id: mainStageAppRect
368 x: mainStage.x
369 y: mainStage.y + mainStage.normalApplicationY
370 width: mainStage.width
371 height: mainStage.height
372 visible: false; enabled: false
373 }
374 Item {
375 id: sideStageAppRect
376 x: sideStageRevealer.openedValue
377 y: sideStage.y + sideStage.normalApplicationY
378 width: sideStage.width
379 height: sideStage.height
380 visible: false; enabled: false
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
418 pinLength: 4
420 onEntered: LightDM.Greeter.respond(passphrase);
421 onCancel: greeter.show()
423 Component.onCompleted: {
424 if (LightDM.Users.count == 1) {
425 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
426 greeter.selected(0)
427 }
428 }
429 }
431 Connections {
432 target: LightDM.Greeter
434 onShowPrompt: {
435 if (LightDM.Users.count == 1) {
436 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
437 if (text == "PIN") {
438 lockscreen.alphaNumeric = false
439 } else {
440 lockscreen.alphaNumeric = true
441 }
442 lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
443 lockscreen.show();
444 }
445 }
447 onAuthenticationComplete: {
448 if (LightDM.Greeter.promptless) {
449 return;
450 }
451 if (LightDM.Greeter.authenticated) {
452 lockscreen.hide();
453 } else {
454 lockscreen.clear(true);
455 }
456 }
457 }
459 Greeter {
460 id: greeter
461 objectName: "greeter"
463 available: true
464 hides: [launcher, panel.indicators, hud]
465 shown: true
467 defaultBackground: shell.background
469 y: panel.panelHeight
470 width: parent.width
471 height: parent.height - panel.panelHeight
473 dragHandleWidth: shell.edgeSize
475 property var previousMainApp: null
476 property var previousSideApp: null
478 function removeApplicationFocus() {
479 greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
480 if (sideStage.fullyShown) { // if side stage hidden, don't focus it on restore
481 greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
482 }
483 applicationManager.unfocusCurrentApplication();
484 }
486 function restoreApplicationFocus() {
487 if (greeter.previousMainApp) {
488 applicationManager.focusApplication(greeter.previousMainApp);
489 greeter.previousMainApp = null;
490 }
491 if (greeter.previousSideApp) {
492 applicationManager.focusApplication(greeter.previousSideApp);
493 greeter.previousSideApp = null;
494 }
495 }
497 onShownChanged: {
498 if (shown) {
499 lockscreen.reset();
500 // If there is only one user, we start authenticating with that one here.
501 // If there are more users, the Greeter will handle that
502 if (LightDM.Users.count == 1) {
503 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
504 greeter.selected(0);
505 }
506 greeter.forceActiveFocus();
507 removeApplicationFocus();
508 } else {
509 restoreApplicationFocus();
510 }
511 }
513 onUnlocked: greeter.hide()
514 onSelected: {
515 // Update launcher items for new user
516 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
517 AccountsService.user = user;
518 LauncherModel.setUser(user);
519 }
521 onLeftTeaserPressedChanged: {
522 if (leftTeaserPressed) {
523 launcher.tease();
524 }
525 }
527 Connections {
528 target: applicationManager
529 ignoreUnknownSignals: true
530 // If any app is focused when greeter is open, it's due to a user action
531 // like a snap decision (say, an incoming call).
532 // TODO: these should be protected to only unlock for certain applications / certain usecases
533 // potentially only in connection with a notification.
534 onMainStageFocusedApplicationChanged: {
535 if (greeter.shown && applicationManager.mainStageFocusedApplication) {
536 greeter.previousMainApp = null // make way for new focused app
537 greeter.previousSideApp = null
538 greeter.hide()
539 }
540 }
541 onSideStageFocusedApplicationChanged: {
542 if (greeter.shown && applicationManager.sideStageFocusedApplication) {
543 greeter.previousMainApp = null // make way for new focused app
544 greeter.previousSideApp = null
545 greeter.hide()
546 }
547 }
548 }
549 }
551 InputFilterArea {
552 anchors.fill: parent
553 blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
554 || panel.indicators.shown || hud.shown
555 }
557 Connections {
558 id: powerConnection
559 target: Powerd
561 onDisplayPowerStateChange: {
562 // We ignore any display-off signals when the proximity sensor
563 // is active. This usually indicates something like a phone call.
564 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
565 greeter.showNow();
566 }
568 // No reason to chew demo CPU when user isn't watching
569 if (status == Powerd.Off) {
570 edgeDemo.paused = true;
571 } else if (status == Powerd.On) {
572 edgeDemo.paused = false;
573 }
574 }
575 }
577 function showHome() {
578 var animate = !greeter.shown && !stages.shown
579 greeter.hide()
580 dash.setCurrentScope("clickscope", animate, false)
581 stages.hide()
582 }
584 function hideIndicatorMenu(delay) {
585 panel.hideIndicatorMenu(delay);
586 }
588 Item {
589 id: overlay
591 anchors.fill: parent
593 Panel {
594 id: panel
595 anchors.fill: parent //because this draws indicator menus
596 indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
597 indicators {
598 hides: [launcher]
599 available: edgeDemo.panelEnabled
600 contentEnabled: edgeDemo.panelContentEnabled
601 }
602 fullscreenMode: shell.fullscreenMode
603 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown
605 InputFilterArea {
606 anchors {
607 top: parent.top
608 left: parent.left
609 right: parent.right
610 }
611 height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
612 blockInput: true
613 }
614 }
616 Hud {
617 id: hud
619 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
620 height: parent.height
622 available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && edgeDemo.dashEnabled
623 shown: false
624 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
625 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
627 Connections {
628 target: shell.applicationManager
629 onMainStageFocusedApplicationChanged: hud.hide()
630 onSideStageFocusedApplicationChanged: hud.hide()
631 }
632 }
634 Revealer {
635 id: hudRevealer
637 enabled: hud.shown
638 width: hud.width
639 anchors.left: hud.left
640 height: parent.height
641 target: hud.revealerTarget
642 closedValue: height
643 openedValue: 0
644 direction: Qt.RightToLeft
645 orientation: Qt.Vertical
646 handleSize: hud.handleHeight
647 onCloseClicked: target.hide()
648 }
650 Bottombar {
651 id: bottombar
652 theHud: hud
653 anchors.fill: parent
654 enabled: hud.available
655 applicationIsOnForeground: applicationFocused
656 }
658 InputFilterArea {
659 blockInput: launcher.shown
660 anchors {
661 top: parent.top
662 bottom: parent.bottom
663 left: parent.left
664 }
665 width: launcher.width
666 }
668 Launcher {
669 id: launcher
671 readonly property bool dashSwipe: progress > 0
673 anchors.top: parent.top
674 anchors.bottom: parent.bottom
675 width: parent.width
676 dragAreaWidth: shell.edgeSize
677 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
679 onShowDashHome: {
680 if (edgeDemo.running)
681 return;
683 showHome()
684 }
685 onDash: {
686 if (stages.shown) {
687 stages.hide();
688 launcher.hide();
689 }
690 }
691 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
692 onLauncherApplicationSelected:{
693 if (edgeDemo.running)
694 return;
696 greeter.hide()
697 shell.activateApplication(appId)
698 }
699 onShownChanged: {
700 if (shown) {
701 panel.indicators.hide()
702 hud.hide()
703 bottombar.hide()
704 }
705 }
706 }
708 Notifications {
709 id: notifications
711 model: NotificationBackend.Model
712 margin: units.gu(1)
714 anchors {
715 top: parent.top
716 right: parent.right
717 bottom: parent.bottom
718 topMargin: panel.panelHeight
719 }
720 states: [
721 State {
722 name: "narrow"
723 when: overlay.width <= units.gu(60)
724 AnchorChanges { target: notifications; anchors.left: parent.left }
725 },
726 State {
727 name: "wide"
728 when: overlay.width > units.gu(60)
729 AnchorChanges { target: notifications; anchors.left: undefined }
730 PropertyChanges { target: notifications; width: units.gu(38) }
731 }
732 ]
734 InputFilterArea {
735 anchors { left: parent.left; right: parent.right }
736 height: parent.contentHeight
737 blockInput: height > 0
738 }
739 }
740 }
742 focus: true
743 onFocusChanged: if (!focus) forceActiveFocus();
745 InputFilterArea {
746 anchors {
747 top: parent.top
748 bottom: parent.bottom
749 left: parent.left
750 }
751 width: shell.edgeSize
752 blockInput: true
753 }
755 InputFilterArea {
756 anchors {
757 top: parent.top
758 bottom: parent.bottom
759 right: parent.right
760 }
761 width: shell.edgeSize
762 blockInput: true
763 }
765 Binding {
766 target: i18n
767 property: "domain"
768 value: "unity8"
769 }
771 Label {
772 anchors.centerIn: parent
773 visible: applicationManager.fake
774 text: "EARLY ALPHA\nNOT READY FOR USE"
775 color: "lightgrey"
776 opacity: 0.2
777 font.weight: Font.Black
778 horizontalAlignment: Text.AlignHCenter
779 verticalAlignment: Text.AlignVCenter
780 fontSizeMode: Text.Fit
781 rotation: -45
782 scale: Math.min(parent.width, parent.height) / width
783 }
785 EdgeDemo {
786 id: edgeDemo
787 greeter: greeter
788 launcher: launcher
789 dash: dash
790 indicators: panel.indicators
791 underlay: underlay
792 }
794 Connections {
795 target: SessionBroadcast
796 onShowHome: showHome()
797 }