on 4fe5d4e help sign in
unity8/qml/Shell.qml
797 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
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 applicationRunning: ((mainStage.applications && mainStage.applications.count > 0)
147 || (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 applicationSurfaceShouldBeSeen: applicationRunning && !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 && !applicationSurfaceShouldBeSeen
159 Rectangle {
160 anchors.fill: parent
161 color: "black"
162 opacity: dash.disappearingAnimationProgress
163 }
165 Image {
166 anchors.fill: dash
167 source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
168 fillMode: Image.PreserveAspectCrop
169 horizontalAlignment: Image.AlignRight
170 verticalAlignment: Image.AlignTop
171 }
173 Dash {
174 id: dash
175 objectName: "dash"
177 available: !greeter.shown && !lockscreen.shown
178 hides: [stages, launcher, panel.indicators]
179 shown: disappearingAnimationProgress !== 1.0
180 enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
181 // FIXME: unfocus all applications when going back to the dash
182 onEnabledChanged: {
183 if (enabled) {
184 shell.applicationManager.unfocusCurrentApplication()
185 }
186 }
188 anchors {
189 fill: parent
190 topMargin: panel.panelHeight
191 }
193 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
194 opacity: 1.0 - disappearingAnimationProgress
195 property real disappearingAnimationProgress: {
196 if (greeter.shown) {
197 return greeter.showProgress;
198 } else {
199 return stagesOuterContainer.showProgress;
200 }
201 }
203 // FIXME: only necessary because stagesOuterContainer.showProgress and
204 // greeterRevealer.animatedProgress are not animated
205 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
206 }
207 }
209 Item {
210 id: stagesOuterContainer
212 width: parent.width
213 height: parent.height
214 x: launcher.progress
215 Behavior on x {SmoothedAnimation{velocity: 600}}
217 property real showProgress:
218 MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
220 Showable {
221 id: stages
222 objectName: "stages"
224 x: width
226 property bool fullyShown: shown && x == 0 && parent.x == 0
227 property bool fullyHidden: !shown && x == width
228 available: !greeter.shown
229 hides: [panel.indicators]
230 shown: false
231 opacity: 1.0
232 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
233 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
235 width: parent.width
236 height: parent.height
238 // close the stages when no focused application remains
239 Connections {
240 target: shell.applicationManager
241 onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
242 onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
243 ignoreUnknownSignals: true
244 }
246 function closeIfNoApplications() {
247 if (!shell.applicationManager.mainStageFocusedApplication
248 && !shell.applicationManager.sideStageFocusedApplication
249 && shell.applicationManager.mainStageApplications.count == 0
250 && shell.applicationManager.sideStageApplications.count == 0) {
251 stages.hide();
252 }
253 }
255 // show the stages when an application gets the focus
256 Connections {
257 target: shell.applicationManager
258 onMainStageFocusedApplicationChanged: {
259 if (shell.applicationManager.mainStageFocusedApplication) {
260 mainStage.show();
261 stages.show();
262 }
263 }
264 onSideStageFocusedApplicationChanged: {
265 if (shell.applicationManager.sideStageFocusedApplication) {
266 sideStage.show();
267 stages.show();
268 }
269 }
270 ignoreUnknownSignals: true
271 }
273 Stage {
274 id: mainStage
276 anchors.fill: parent
277 fullyShown: stages.fullyShown
278 fullyHidden: stages.fullyHidden
279 shouldUseScreenshots: !fullyShown
280 rightEdgeEnabled: !sideStage.enabled
282 applicationManager: shell.applicationManager
283 rightEdgeDraggingAreaWidth: shell.edgeSize
284 normalApplicationY: shell.panelHeight
286 shown: true
287 function show() {
288 stages.show();
289 }
290 function hide() {
291 }
293 // FIXME: workaround the fact that focusing a main stage application
294 // raises its surface on top of all other surfaces including the ones
295 // that belong to side stage applications.
296 onFocusedApplicationChanged: {
297 if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
298 shell.applicationManager.focusApplication(sideStage.focusedApplication);
299 }
300 }
301 }
303 SideStage {
304 id: sideStage
306 applicationManager: shell.applicationManager
307 rightEdgeDraggingAreaWidth: shell.edgeSize
308 normalApplicationY: shell.panelHeight
310 onShownChanged: {
311 if (!shown && mainStage.applications.count == 0) {
312 stages.hide();
313 }
314 }
315 // FIXME: when hiding the side stage, refocus the main stage
316 // application so that it goes in front of the side stage
317 // application and hides it
318 onFullyShownChanged: {
319 if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
320 shell.applicationManager.focusApplication(mainStage.focusedApplication);
321 }
322 }
324 enabled: shell.width >= units.gu(60)
325 visible: enabled
326 fullyShown: stages.fullyShown && shown
327 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
328 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
330 available: !greeter.shown && !lockscreen.shown && enabled
331 hides: [launcher, panel.indicators]
332 shown: false
333 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
334 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
336 width: units.gu(40)
337 height: stages.height
338 handleExpanded: sideStageRevealer.pressed
339 }
341 Revealer {
342 id: sideStageRevealer
344 enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
345 && sideStage.available
346 direction: Qt.RightToLeft
347 openedValue: parent.width - sideStage.width
348 hintDisplacement: units.gu(3)
349 /* The size of the sidestage handle needs to be bigger than the
350 typical size used for edge detection otherwise it is really
351 hard to grab.
352 */
353 handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
354 closedValue: parent.width + sideStage.handleSizeCollapsed
355 target: sideStage
356 x: parent.width - width
357 width: sideStage.width + handleSize * 0.7
358 height: sideStage.height
359 orientation: Qt.Horizontal
360 }
362 // Defines the rectangle occupied by an application on the main or side stage.
363 // Used only to inform the ApplicationManager. Can be removed when the proper
364 // architecture is in place (unity8 as mir compositor).
365 Item {
366 id: mainStageAppRect
367 x: mainStage.x
368 y: mainStage.y + mainStage.normalApplicationY
369 width: mainStage.width
370 height: mainStage.height
371 visible: false; enabled: false
372 }
373 Item {
374 id: sideStageAppRect
375 x: sideStageRevealer.openedValue
376 y: sideStage.y + sideStage.normalApplicationY
377 width: sideStage.width
378 height: sideStage.height
379 visible: false; enabled: false
380 }
382 DragHandle {
383 id: stagesDragHandle
385 anchors.top: parent.top
386 anchors.bottom: parent.bottom
387 anchors.right: parent.left
389 width: shell.edgeSize
390 direction: Direction.Leftwards
391 enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled
392 property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
394 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
395 // Make autocompletion impossible when !haveApps
396 edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
397 }
398 }
399 }
401 Lockscreen {
402 id: lockscreen
403 objectName: "lockscreen"
405 readonly property int backgroundTopMargin: -panel.panelHeight
407 hides: [launcher, panel.indicators, hud]
408 shown: false
409 enabled: true
410 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
411 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
412 y: panel.panelHeight
413 x: required ? 0 : - width
414 width: parent.width
415 height: parent.height - panel.panelHeight
416 background: shell.background
417 pinLength: 4
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 if (sideStage.fullyShown) { // if side stage hidden, don't focus it on restore
480 greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
481 }
482 applicationManager.unfocusCurrentApplication();
483 }
485 function restoreApplicationFocus() {
486 if (greeter.previousMainApp) {
487 applicationManager.focusApplication(greeter.previousMainApp);
488 greeter.previousMainApp = null;
489 }
490 if (greeter.previousSideApp) {
491 applicationManager.focusApplication(greeter.previousSideApp);
492 greeter.previousSideApp = null;
493 }
494 }
496 onShownChanged: {
497 if (shown) {
498 lockscreen.reset();
499 // If there is only one user, we start authenticating with that one here.
500 // If there are more users, the Greeter will handle that
501 if (LightDM.Users.count == 1) {
502 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
503 greeter.selected(0);
504 }
505 greeter.forceActiveFocus();
506 removeApplicationFocus();
507 } else {
508 restoreApplicationFocus();
509 }
510 }
512 onUnlocked: greeter.hide()
513 onSelected: {
514 // Update launcher items for new user
515 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
516 AccountsService.user = user;
517 LauncherModel.setUser(user);
518 }
520 onLeftTeaserPressedChanged: {
521 if (leftTeaserPressed) {
522 launcher.tease();
523 }
524 }
526 Connections {
527 target: applicationManager
528 ignoreUnknownSignals: true
529 // If any app is focused when greeter is open, it's due to a user action
530 // like a snap decision (say, an incoming call).
531 // TODO: these should be protected to only unlock for certain applications / certain usecases
532 // potentially only in connection with a notification.
533 onMainStageFocusedApplicationChanged: {
534 if (greeter.shown && applicationManager.mainStageFocusedApplication) {
535 greeter.previousMainApp = null // make way for new focused app
536 greeter.previousSideApp = null
537 greeter.hide()
538 }
539 }
540 onSideStageFocusedApplicationChanged: {
541 if (greeter.shown && applicationManager.sideStageFocusedApplication) {
542 greeter.previousMainApp = null // make way for new focused app
543 greeter.previousSideApp = null
544 greeter.hide()
545 }
546 }
547 }
548 }
550 InputFilterArea {
551 anchors.fill: parent
552 blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
553 || panel.indicators.shown || hud.shown
554 }
556 Connections {
557 id: powerConnection
558 target: Powerd
560 onDisplayPowerStateChange: {
561 // We ignore any display-off signals when the proximity sensor
562 // is active. This usually indicates something like a phone call.
563 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
564 greeter.showNow();
565 }
567 // No reason to chew demo CPU when user isn't watching
568 if (status == Powerd.Off) {
569 edgeDemo.paused = true;
570 } else if (status == Powerd.On) {
571 edgeDemo.paused = false;
572 }
573 }
574 }
576 function showHome() {
577 var animate = !greeter.shown && !stages.shown
578 greeter.hide()
579 dash.setCurrentScope("clickscope", animate, false)
580 stages.hide()
581 }
583 function hideIndicatorMenu(delay) {
584 panel.hideIndicatorMenu(delay);
585 }
587 Item {
588 id: overlay
590 anchors.fill: parent
592 Panel {
593 id: panel
594 anchors.fill: parent //because this draws indicator menus
595 indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
596 indicators {
597 hides: [launcher]
598 available: edgeDemo.panelEnabled
599 contentEnabled: edgeDemo.panelContentEnabled
600 }
601 fullscreenMode: shell.fullscreenMode
602 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown
604 InputFilterArea {
605 anchors {
606 top: parent.top
607 left: parent.left
608 right: parent.right
609 }
610 height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
611 blockInput: true
612 }
613 }
615 Hud {
616 id: hud
618 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
619 height: parent.height
621 available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && edgeDemo.dashEnabled
622 shown: false
623 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
624 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
626 Connections {
627 target: shell.applicationManager
628 onMainStageFocusedApplicationChanged: hud.hide()
629 onSideStageFocusedApplicationChanged: hud.hide()
630 }
631 }
633 Revealer {
634 id: hudRevealer
636 enabled: hud.shown
637 width: hud.width
638 anchors.left: hud.left
639 height: parent.height
640 target: hud.revealerTarget
641 closedValue: height
642 openedValue: 0
643 direction: Qt.RightToLeft
644 orientation: Qt.Vertical
645 handleSize: hud.handleHeight
646 onCloseClicked: target.hide()
647 }
649 Bottombar {
650 id: bottombar
651 theHud: hud
652 anchors.fill: parent
653 enabled: hud.available
654 applicationIsOnForeground: applicationFocused
655 }
657 InputFilterArea {
658 blockInput: launcher.shown
659 anchors {
660 top: parent.top
661 bottom: parent.bottom
662 left: parent.left
663 }
664 width: launcher.width
665 }
667 Launcher {
668 id: launcher
670 readonly property bool dashSwipe: progress > 0
672 anchors.top: parent.top
673 anchors.bottom: parent.bottom
674 width: parent.width
675 dragAreaWidth: shell.edgeSize
676 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
678 onShowDashHome: {
679 if (edgeDemo.running)
680 return;
682 showHome()
683 }
684 onDash: {
685 if (stages.shown) {
686 stages.hide();
687 launcher.hide();
688 }
689 }
690 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
691 onLauncherApplicationSelected:{
692 if (edgeDemo.running)
693 return;
695 greeter.hide()
696 shell.activateApplication(appId)
697 }
698 onShownChanged: {
699 if (shown) {
700 panel.indicators.hide()
701 hud.hide()
702 bottombar.hide()
703 }
704 }
705 }
707 Notifications {
708 id: notifications
710 model: NotificationBackend.Model
711 margin: units.gu(1)
713 anchors {
714 top: parent.top
715 right: parent.right
716 bottom: parent.bottom
717 topMargin: panel.panelHeight
718 }
719 states: [
720 State {
721 name: "narrow"
722 when: overlay.width <= units.gu(60)
723 AnchorChanges { target: notifications; anchors.left: parent.left }
724 },
725 State {
726 name: "wide"
727 when: overlay.width > units.gu(60)
728 AnchorChanges { target: notifications; anchors.left: undefined }
729 PropertyChanges { target: notifications; width: units.gu(38) }
730 }
731 ]
733 InputFilterArea {
734 anchors { left: parent.left; right: parent.right }
735 height: parent.contentHeight
736 blockInput: height > 0
737 }
738 }
739 }
741 focus: true
742 onFocusChanged: if (!focus) forceActiveFocus();
744 InputFilterArea {
745 anchors {
746 top: parent.top
747 bottom: parent.bottom
748 left: parent.left
749 }
750 width: shell.edgeSize
751 blockInput: true
752 }
754 InputFilterArea {
755 anchors {
756 top: parent.top
757 bottom: parent.bottom
758 right: parent.right
759 }
760 width: shell.edgeSize
761 blockInput: true
762 }
764 Binding {
765 target: i18n
766 property: "domain"
767 value: "unity8"
768 }
770 Label {
771 anchors.centerIn: parent
772 visible: applicationManager.fake
773 text: "EARLY ALPHA\nNOT READY FOR USE"
774 color: "lightgrey"
775 opacity: 0.2
776 font.weight: Font.Black
777 horizontalAlignment: Text.AlignHCenter
778 verticalAlignment: Text.AlignVCenter
779 fontSizeMode: Text.Fit
780 rotation: -45
781 scale: Math.min(parent.width, parent.height) / width
782 }
784 EdgeDemo {
785 id: edgeDemo
786 greeter: greeter
787 launcher: launcher
788 dash: dash
789 indicators: panel.indicators
790 underlay: underlay
791 }
793 Connections {
794 target: SessionBroadcast
795 onShowHome: showHome()
796 }