on 13eb553 help sign in
unity8/qml/Shell.qml
880 lines 31 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 QtQuick.Window 2.0
19import AccountsService 0.1
20import GSettings 1.0
21import Unity.Application 0.1
22import Ubuntu.Components 0.1
23import Ubuntu.Components.Popups 1.0
24import Ubuntu.Gestures 0.1
25import Ubuntu.SystemImage 0.1
26import Ubuntu.Telephony 0.1 as Telephony
27import Unity.Connectivity 0.1
28import Unity.Launcher 0.1
29import Utils 0.1
30import LightDM 0.1 as LightDM
31import Powerd 0.1
32import SessionBroadcast 0.1
33import "Greeter"
34import "Launcher"
35import "Panel"
36import "Components"
37import "Notifications"
38import "Stages"
39import "Panel/Indicators"
40import "Wizard"
41import Unity.Notifications 1.0 as NotificationBackend
42import Unity.Session 0.1
43import Unity.DashCommunicator 0.1
45Item {
46 id: shell
48 // Disable everything so that user can't swipe greeter or launcher until
49 // we get first prompt/authenticate, which will re-enable the shell.
50 enabled: false
52 // this is only here to select the width / height of the window if not running fullscreen
53 property bool tablet: false
54 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
55 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
57 property real edgeSize: units.gu(2)
58 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
59 property url background: asImageTester.status == Image.Ready ? asImageTester.source
60 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
61 readonly property real panelHeight: panel.panelHeight
63 readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock
64 readonly property alias hasLockedApp: greeter.hasLockedApp
65 readonly property bool forcedUnlock: edgeDemo.running
66 onForcedUnlockChanged: if (forcedUnlock) lockscreen.hide()
68 property bool sideStageEnabled: shell.width >= units.gu(100)
69 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
71 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
72 property int failedLoginsDelayAttempts: 7 // number of failed logins
73 property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
75 property int orientation
76 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
77 onDeviceOrientationAngleChanged: {
78 if (!OrientationLock.enabled) {
79 orientation = Screen.orientation;
80 }
81 }
82 readonly property bool orientationLockEnabled: OrientationLock.enabled
83 onOrientationLockEnabledChanged: {
84 if (orientationLockEnabled) {
85 OrientationLock.savedOrientation = Screen.orientation;
86 } else {
87 orientation = Screen.orientation;
88 }
89 }
91 function activateApplication(appId) {
92 if (ApplicationManager.findApplication(appId)) {
93 ApplicationManager.requestFocusApplication(appId);
94 } else {
95 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
96 ApplicationManager.startApplication(appId, execFlags);
97 }
98 }
100 function startLockedApp(app) {
101 if (shell.locked) {
102 greeter.lockedApp = app;
103 }
104 shell.activateApplication(app);
105 }
107 // This is a dummy image to detect if the custom AS set wallpaper loads successfully.
108 Image {
109 id: asImageTester
110 source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : ""
111 height: 0
112 width: 0
113 sourceSize.height: 0
114 sourceSize.width: 0
115 }
117 GSettings {
118 id: backgroundSettings
119 schema.id: "org.gnome.desktop.background"
120 }
122 // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully.
123 Image {
124 id: gsImageTester
125 source: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : ""
126 height: 0
127 width: 0
128 sourceSize.height: 0
129 sourceSize.width: 0
130 }
132 GSettings {
133 id: usageModeSettings
134 schema.id: "com.canonical.Unity8"
135 }
137 Binding {
138 target: LauncherModel
139 property: "applicationManager"
140 value: ApplicationManager
141 }
143 Component.onCompleted: {
144 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
145 if (ApplicationManager.count > 0) {
146 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
147 }
148 if (orientationLockEnabled) {
149 orientation = OrientationLock.savedOrientation;
150 }
151 }
153 VolumeControl {
154 id: volumeControl
155 }
157 DashCommunicator {
158 id: dash
159 objectName: "dashCommunicator"
160 }
162 PhysicalKeysMapper {
163 id: physicalKeysMapper
165 onVolumeDownPressed: volumeControl.volumeDown()
166 onVolumeUpPressed: volumeControl.volumeUp()
167 onScreenshotPressed: screenGrabber.capture()
168 }
170 ScreenGrabber {
171 id: screenGrabber
172 z: edgeDemo.z + 10
173 enabled: Powerd.status === Powerd.On
174 }
176 Binding {
177 target: ApplicationManager
178 property: "forceDashActive"
179 value: launcher.shown || launcher.dashSwipe
180 }
182 WindowKeysFilter {
183 Keys.onPressed: {
184 physicalKeysMapper.onKeyPressed(event.key);
185 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
186 event.accepted = true;
187 } else {
188 event.accepted = false;
189 }
190 }
192 Keys.onReleased: {
193 physicalKeysMapper.onKeyReleased(event.key);
194 if (event.key = Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
195 event.accepted = true;
196 } else {
197 event.accepted = false;
198 }
199 }
200 }
202 Item {
203 id: stages
204 objectName: "stages"
205 width: parent.width
206 height: parent.height
207 visible: !ApplicationManager.empty
209 Connections {
210 target: ApplicationManager
211 onFocusRequested: {
212 if (greeter.narrowMode) {
213 if (appId === "dialer-app" && callManager.hasCalls && shell.locked) {
214 // If we are in the middle of a call, make dialer lockedApp and show it.
215 // This can happen if user backs out of dialer back to greeter, then
216 // launches dialer again.
217 greeter.lockedApp = appId;
218 }
219 if (greeter.hasLockedApp) {
220 if (appId === greeter.lockedApp) {
221 lockscreen.hide() // show locked app
222 } else {
223 greeter.startUnlock() // show lockscreen if necessary
224 }
225 }
226 greeter.hide();
227 } else {
228 if (LightDM.Greeter.active) {
229 greeter.startUnlock()
230 }
231 }
232 }
234 onFocusedApplicationIdChanged: {
235 if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
236 greeter.startUnlock()
237 }
238 panel.indicators.hide();
239 }
241 onApplicationAdded: {
242 if (greeter.shown && appId != "unity8-dash") {
243 greeter.startUnlock()
245 // If this happens on first boot, we may be in edge
246 // tutorial or wizard while receiving a call. But a call
247 // is more important than wizard so just bail out of those.
248 if (edgeDemo.running) {
249 edgeDemo.hideEdgeDemos();
250 wizard.hide();
251 }
252 }
253 if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
254 lockscreen.hide() // show locked app
255 }
256 launcher.hide();
257 }
258 }
260 Loader {
261 id: applicationsDisplayLoader
262 objectName: "applicationsDisplayLoader"
263 anchors.fill: parent
265 // When we have a locked app, we only want to show that one app.
266 // FIXME: do this in a less traumatic way. We currently only allow
267 // locked apps in phone mode (see FIXME in Lockscreen component in
268 // this same file). When that changes, we need to do something
269 // nicer here. But this code is currently just to prevent a
270 // theoretical attack where user enters lockedApp mode, then makes
271 // the screen larger (maybe connects to monitor) and tries to enter
272 // tablet mode.
273 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
274 source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml"
275 : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
277 Binding {
278 target: applicationsDisplayLoader.item
279 property: "objectName"
280 value: "stage"
281 }
282 Binding {
283 target: applicationsDisplayLoader.item
284 property: "dragAreaWidth"
285 value: shell.edgeSize
286 }
287 Binding {
288 target: applicationsDisplayLoader.item
289 property: "maximizedAppTopMargin"
290 // Not just using panel.panelHeight as that changes depending on the focused app.
291 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
292 }
293 Binding {
294 target: applicationsDisplayLoader.item
295 property: "interactive"
296 value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0 && !notifications.useModal
297 }
298 Binding {
299 target: applicationsDisplayLoader.item
300 property: "spreadEnabled"
301 value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
302 }
303 Binding {
304 target: applicationsDisplayLoader.item
305 property: "inverseProgress"
306 value: launcher.progress
307 }
308 Binding {
309 target: applicationsDisplayLoader.item
310 property: "orientation"
311 value: shell.orientation
312 }
313 Binding {
314 target: applicationsDisplayLoader.item
315 property: "background"
316 value: shell.background
317 }
318 }
319 }
321 InputMethod {
322 id: inputMethod
323 objectName: "inputMethod"
324 anchors { fill: parent; topMargin: panel.panelHeight }
325 z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
326 }
328 Connections {
329 target: SurfaceManager
330 onSurfaceCreated: {
331 if (surface.type == MirSurfaceItem.InputMethod) {
332 inputMethod.surface = surface;
333 }
334 }
336 onSurfaceDestroyed: {
337 if (inputMethod.surface == surface) {
338 inputMethod.surface = null;
339 surface.parent = null;
340 }
341 if (!surface.parent) {
342 // there's no one displaying it. delete it right away
343 surface.release();
344 }
345 }
346 }
347 Connections {
348 target: SessionManager
349 onSessionStopping: {
350 if (!session.parentSession && !session.application) {
351 // nothing is using it. delete it right away
352 session.release();
353 }
354 }
355 }
357 Lockscreen {
358 id: lockscreen
359 objectName: "lockscreen"
361 hides: [launcher, panel.indicators]
362 shown: false
363 enabled: true
364 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
365 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
366 y: panel.panelHeight
367 visible: required
368 width: parent.width
369 height: parent.height - panel.panelHeight
370 background: shell.background
371 darkenBackground: 0.4
372 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
373 minPinLength: 4
374 maxPinLength: 4
376 property string promptText
377 infoText: promptText !== "" ? i18n.tr("Enter %1").arg(promptText) :
378 alphaNumeric ? i18n.tr("Enter passphrase") :
379 i18n.tr("Enter passcode")
380 errorText: promptText !== "" ? i18n.tr("Sorry, incorrect %1").arg(promptText) :
381 alphaNumeric ? i18n.tr("Sorry, incorrect passphrase") + "\n" +
382 i18n.tr("Please re-enter") :
383 i18n.tr("Sorry, incorrect passcode")
385 // FIXME: We *should* show emergency dialer if there is a SIM present,
386 // regardless of whether the side stage is enabled. But right now,
387 // the assumption is that narrow screens are phones which have SIMs
388 // and wider screens are tablets which don't. When we do allow this
389 // on devices with a side stage and a SIM, work should be done to
390 // ensure that the main stage is disabled while the dialer is present
391 // in the side stage. See the FIXME in the stage loader in this file.
392 showEmergencyCallButton: !shell.sideStageEnabled
394 onEntered: LightDM.Greeter.respond(passphrase);
395 onCancel: greeter.show()
396 onEmergencyCall: startLockedApp("dialer-app")
398 onShownChanged: if (shown) greeter.lockedApp = ""
400 function maybeShow() {
401 if (!shell.forcedUnlock) {
402 show()
403 }
404 }
406 Timer {
407 id: forcedDelayTimer
408 interval: 1000 * 60
409 onTriggered: {
410 if (lockscreen.delayMinutes > 0) {
411 lockscreen.delayMinutes -= 1
412 if (lockscreen.delayMinutes > 0) {
413 start() // go again
414 }
415 }
416 }
417 }
419 Component.onCompleted: {
420 if (greeter.narrowMode) {
421 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
422 }
423 }
424 }
426 Connections {
427 target: LightDM.Greeter
429 onShowGreeter: greeter.show()
430 onHideGreeter: greeter.login()
432 onShowPrompt: {
433 shell.enabled = true;
434 if (!LightDM.Greeter.active) {
435 return; // could happen if hideGreeter() comes in before we prompt
436 }
437 if (greeter.narrowMode) {
438 lockscreen.promptText = isDefaultPrompt ? "" : text.toLowerCase();
439 lockscreen.maybeShow();
440 }
441 }
443 onPromptlessChanged: {
444 if (!LightDM.Greeter.active) {
445 return; // could happen if hideGreeter() comes in before we prompt
446 }
447 if (greeter.narrowMode) {
448 if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
449 lockscreen.hide()
450 } else {
451 lockscreen.reset();
452 lockscreen.maybeShow();
453 }
454 }
455 }
457 onAuthenticationComplete: {
458 shell.enabled = true;
459 if (LightDM.Greeter.authenticated) {
460 AccountsService.failedLogins = 0
461 }
462 // Else only penalize user for a failed login if they actually were
463 // prompted for a password. We do this below after the promptless
464 // early exit.
466 if (LightDM.Greeter.promptless) {
467 return;
468 }
470 if (LightDM.Greeter.authenticated) {
471 greeter.login();
472 } else {
473 AccountsService.failedLogins++
474 if (maxFailedLogins >= 2) { // require at least a warning
475 if (AccountsService.failedLogins === maxFailedLogins - 1) {
476 var title = lockscreen.alphaNumeric ?
477 i18n.tr("Sorry, incorrect passphrase.") :
478 i18n.tr("Sorry, incorrect passcode.")
479 var text = i18n.tr("This will be your last attempt.") + " " +
480 (lockscreen.alphaNumeric ?
481 i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
482 i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
483 lockscreen.showInfoPopup(title, text)
484 } else if (AccountsService.failedLogins >= maxFailedLogins) {
485 SystemImage.factoryReset() // Ouch!
486 }
487 }
488 if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
489 lockscreen.delayMinutes = failedLoginsDelayMinutes
490 forcedDelayTimer.start()
491 }
493 lockscreen.clear(true);
494 if (greeter.narrowMode) {
495 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
496 }
497 }
498 }
499 }
501 Binding {
502 target: LightDM.Greeter
503 property: "active"
504 value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
505 }
507 Rectangle {
508 anchors.fill: parent
509 color: "black"
510 opacity: greeterWrapper.showProgress * 0.8
511 }
513 Item {
514 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
515 id: greeterWrapper
516 objectName: "greeterWrapper"
517 x: (greeter.narrowMode && greeter.showProgress > 0) ? launcher.progress : 0
518 y: panel.panelHeight
519 width: parent.width
520 height: parent.height - panel.panelHeight
522 Behavior on x {
523 enabled: !launcher.dashSwipe
524 StandardAnimation {}
525 }
527 property bool fullyShown: showProgress === 1.0
528 onFullyShownChanged: {
529 // Wait until the greeter is completely covering lockscreen before resetting it.
530 if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
531 lockscreen.reset();
532 lockscreen.maybeShow();
533 }
534 }
536 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
537 onShowProgressChanged: {
538 if (showProgress === 0) {
539 if ((LightDM.Greeter.promptless && LightDM.Greeter.authenticated) || shell.forcedUnlock) {
540 greeter.login()
541 } else if (greeter.narrowMode) {
542 lockscreen.clear(false) // to reset focus if necessary
543 }
544 }
545 }
547 Greeter {
548 id: greeter
549 objectName: "greeter"
551 signal sessionStarted() // helpful for tests
553 property string lockedApp: ""
554 property bool hasLockedApp: lockedApp !== ""
556 hides: [launcher, panel.indicators]
557 loadContent: required || lockscreen.required // keeps content in memory for quick show()
559 locked: shell.locked
561 background: shell.background
563 width: parent.width
564 height: parent.height
567 // avoid overlapping with Launcher's edge drag area
568 // FIXME: Fix TouchRegistry & friends and remove this workaround
569 // Issue involves launcher's DDA getting disabled on a long
570 // left-edge drag
571 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
573 function startUnlock() {
574 if (narrowMode) {
575 if (!LightDM.Greeter.authenticated) {
576 lockscreen.maybeShow()
577 }
578 hide()
579 } else {
580 show()
581 tryToUnlock()
582 }
583 }
585 function login() {
586 enabled = false;
587 if (LightDM.Greeter.startSessionSync()) {
588 sessionStarted();
589 greeter.hide();
590 lockscreen.hide();
591 launcher.hide();
592 }
593 enabled = true;
594 }
596 onShownChanged: {
597 if (shown) {
598 // Disable everything so that user can't swipe greeter or
599 // launcher until we get the next prompt/authenticate, which
600 // will re-enable the shell.
601 shell.enabled = false;
603 if (greeter.narrowMode) {
604 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
605 } else {
606 reset()
607 }
608 greeter.lockedApp = "";
609 greeter.forceActiveFocus();
610 }
611 }
613 Component.onCompleted: {
614 Connectivity.unlockAllModems()
615 }
617 onUnlocked: greeter.hide()
618 onSelected: {
619 // Update launcher items for new user
620 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
621 AccountsService.user = user;
622 LauncherModel.setUser(user);
623 }
625 onTapped: launcher.tease()
626 onDraggingChanged: {
627 if (dragging) {
628 launcher.tease();
629 }
630 }
632 Binding {
633 target: ApplicationManager
634 property: "suspended"
635 value: (greeter.shown && greeterWrapper.showProgress == 1) || lockscreen.shown
636 }
637 }
638 }
640 Connections {
641 id: callConnection
642 target: callManager
644 onHasCallsChanged: {
645 if (shell.locked && callManager.hasCalls) {
646 // We just received an incoming call while locked. The
647 // indicator will have already launched dialer-app for us, but
648 // there is a race between "hasCalls" changing and the dialer
649 // starting up. So in case we lose that race, we'll start/
650 // focus the dialer ourselves here too. Even if the indicator
651 // didn't launch the dialer for some reason (or maybe a call
652 // started via some other means), if an active call is
653 // happening, we want to be in the dialer.
654 startLockedApp("dialer-app")
655 }
656 }
657 }
659 Connections {
660 id: powerConnection
661 target: Powerd
663 onStatusChanged: {
664 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
665 !callManager.hasCalls && !edgeDemo.running) {
666 greeter.showNow()
667 }
668 }
669 }
671 function showHome() {
672 if (edgeDemo.running) {
673 return
674 }
676 if (LightDM.Greeter.active) {
677 greeter.startUnlock()
678 }
680 var animate = !LightDM.Greeter.active && !stages.shown
681 dash.setCurrentScope(0, animate, false)
682 ApplicationManager.requestFocusApplication("unity8-dash")
683 }
685 function showDash() {
686 if (greeter.hasLockedApp || // just in case user gets here
687 (!greeter.narrowMode && shell.locked)) {
688 return
689 }
691 if (greeter.shown) {
692 greeter.hideRight();
693 launcher.fadeOut();
694 }
696 if (ApplicationManager.focusedApplicationId != "unity8-dash") {
697 ApplicationManager.requestFocusApplication("unity8-dash")
698 launcher.fadeOut();
699 }
700 }
702 Item {
703 id: overlay
704 z: 10
706 anchors.fill: parent
708 Panel {
709 id: panel
710 objectName: "panel"
711 anchors.fill: parent //because this draws indicator menus
712 indicators {
713 hides: [launcher]
714 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
715 contentEnabled: edgeDemo.panelContentEnabled
716 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
718 minimizedPanelHeight: units.gu(3)
719 expandedPanelHeight: units.gu(7)
721 indicatorsModel: visibleIndicators.model
722 }
724 VisibleIndicators {
725 id: visibleIndicators
726 // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
727 Component.onCompleted: initialise(indicatorProfile)
728 }
729 callHint {
730 greeterShown: greeter.shown || lockscreen.shown
731 }
733 property bool topmostApplicationIsFullscreen:
734 ApplicationManager.focusedApplicationId &&
735 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
737 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
738 || greeter.hasLockedApp
739 }
741 Launcher {
742 id: launcher
743 objectName: "launcher"
745 readonly property bool dashSwipe: progress > 0
747 anchors.top: parent.top
748 anchors.topMargin: inverted ? 0 : panel.panelHeight
749 anchors.bottom: parent.bottom
750 width: parent.width
751 dragAreaWidth: shell.edgeSize
752 available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
753 inverted: usageModeSettings.usageMode === "Staged"
755 onShowDashHome: showHome()
756 onDash: showDash()
757 onDashSwipeChanged: {
758 if (dashSwipe) {
759 dash.setCurrentScope(0, false, true)
760 }
761 }
762 onLauncherApplicationSelected: {
763 if (greeter.hasLockedApp) {
764 greeter.startUnlock()
765 }
766 if (!edgeDemo.running)
767 shell.activateApplication(appId)
768 }
769 onShownChanged: {
770 if (shown) {
771 panel.indicators.hide()
772 }
773 }
774 }
776 Wizard {
777 id: wizard
778 anchors.fill: parent
779 background: shell.background
780 }
782 Rectangle {
783 id: modalNotificationBackground
785 visible: notifications.useModal && (notifications.state == "narrow")
786 color: "#000000"
787 anchors.fill: parent
788 opacity: 0.9
790 MouseArea {
791 anchors.fill: parent
792 }
793 }
795 Notifications {
796 id: notifications
798 model: NotificationBackend.Model
799 margin: units.gu(1)
801 y: topmostIsFullscreen ? 0 : panel.panelHeight
802 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
804 states: [
805 State {
806 name: "narrow"
807 when: overlay.width <= units.gu(60)
808 AnchorChanges {
809 target: notifications
810 anchors.left: parent.left
811 anchors.right: parent.right
812 }
813 },
814 State {
815 name: "wide"
816 when: overlay.width > units.gu(60)
817 AnchorChanges {
818 target: notifications
819 anchors.left: undefined
820 anchors.right: parent.right
821 }
822 PropertyChanges { target: notifications; width: units.gu(38) }
823 }
824 ]
825 }
826 }
828 Dialogs {
829 id: dialogs
830 anchors.fill: parent
831 z: overlay.z + 10
832 onPowerOffClicked: {
833 shutdownFadeOutRectangle.enabled = true;
834 shutdownFadeOutRectangle.visible = true;
835 shutdownFadeOut.start();
836 }
838 Connections {
839 target: physicalKeysMapper
840 onPowerKeyLongPress: dialogs.showPowerDialog();
841 }
842 }
844 EdgeDemo {
845 id: edgeDemo
846 objectName: "edgeDemo"
847 z: dialogs.z + 10
848 paused: Powerd.status === Powerd.Off || wizard.active // Saves power
849 greeter: greeter
850 launcher: launcher
851 panel: panel
852 stages: stages
853 }
855 Connections {
856 target: SessionBroadcast
857 onShowHome: showHome()
858 }
860 Rectangle {
861 id: shutdownFadeOutRectangle
862 z: edgeDemo.z + 10
863 enabled: false
864 visible: false
865 color: "black"
866 anchors.fill: parent
867 opacity: 0.0
868 NumberAnimation on opacity {
869 id: shutdownFadeOut
870 from: 0.0
871 to: 1.0
872 onStopped: {
873 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
874 DBusUnitySessionService.Shutdown();
875 }
876 }
877 }
878 }